import math
import sys
from ortools.sat.python import cp_model
import copy
import random
from itertools import combinations
from datetime import datetime, timedelta

max_value = sys.maxsize
min_value = -sys.maxsize

def load_without_splitting_car(goods_num,job_type,goods,detail_add_date):
    '''
    不分车模式下的装车，假设车内的货物数量是无限的，把所有货物按照顺序加到车内
    :param goods_num   货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    :param job_type    货物形态 0可代表栈板，1代表件箱，对应于EMS货物的形态，1是件箱，0是栈板，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，订单类型
    :param goods       栈板转换系数，维度1，维度2 =  厂家，转化系数
    :return
    job_total:装车模型，记录每辆车装载的货物量
    job_type_total:每辆车装的货物量(乘了转化系数)，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    job_re:记录每辆车装载的货物在job_data中的编号；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，编号；如[1,0,1]表示第一个厂家第零个订单第一个订单详情
    goods_num_new：装车模型的货物类型，与car相对应，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物类型
    job_re：每辆车装的货物量(没乘转化系数)，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    car_d_type:记录每辆车装载的货物在job_data中的编号；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，编号；如[1,0,1,0]表示第一个厂家第零个订单第一个订单详情第零个货物
    job_total:每辆车装的货物量，相当于car在第四个维度求和；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    job_type_total:每辆车装的总货物类型，与car_type相关；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物类型
    car_d_goods_num:每辆车装的货物数量，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物数量
    '''


    job_total = []
    job_type_total = []
    job_re = []
    car_d_num = []
    car_d_type = []
    car_d_goods_num = []
    goods_num_new = []
    order_sequence = []
    no_car_re = []
    no_job_data_re = []

    for i in range(len(goods_num)):         #厂家层级遍历

        sub_job_total = []
        sub_job_type_total = []
        sub_job_re = []
        sub_car_d_num = []
        sub_car_d_type = []
        sub_car_d_goods_num = []
        sub_goods_num_new = []

        for j in range(len(goods_num[i])):       #订单层级遍历

            sub_sub_job_re = []
            sub_sub_job_total = []
            sub_sub_job_type_total = []
            sub_sub_car_d_num = []
            sub_sub_car_d_type = []
            sub_sub_car_d_goods_num = []
            sub_sub_goods_num_new = []
            sub_goods_num_new_jianxiang = 0
            sub_goods_num_new_zhanban = 0
            sub_job_total_jianxaing = 0
            sub_job_total_zhanban = 0
            if (len(detail_add_date[i][j])>0):
                order_sequence.append([i,j,detail_add_date[i][j][0]])

            for k in range(len(goods_num[i][j])):        #订单详情层级遍历

                for a in range(len(goods_num[i][j][k])):    #货物层级遍历
                    sub_sub_sub_car_d_goods_num = 0
                    sub_sub_car_d_num.append(goods_num[i][j][k][a])     #统计货物数量
                    sub_sub_job_re.append([i, j, k])
                    # for u in range(goods_num[i][j][k][a]):
                    sub_sub_car_d_type.append(job_type[i][j][k][a])     #统计货物类型

                    # sub_sub_car_d_goods_num.append(goods[i][j][k][a])
                    if (job_type[i][j][k][a]==1):                       #如果是件箱，则把货物加到件箱数量中
                        sub_job_total_jianxaing += goods_num[i][j][k][a]
                        # sub_goods_num_new_jianxiang += goods[i][j][k][a]
                    else:                                               #如果是栈板，则把货物加到栈板数量中
                        sub_job_total_zhanban += goods_num[i][j][k][a]
                        # sub_goods_num_new_zhanban += goods[i][j][k][a]
                    if a == 0:
                        for u in range(goods_num[i][j][k][a]):
                            sub_sub_sub_car_d_goods_num += goods[i][j][k][u]    #统计货物数量
                        sub_sub_car_d_goods_num.append(sub_sub_sub_car_d_goods_num)
                    else:
                        for u in range(goods_num[i][j][k][a]):
                            sub_sub_sub_car_d_goods_num += goods[i][j][k][u+goods_num[i][j][k][0]]
                        sub_sub_car_d_goods_num.append(sub_sub_sub_car_d_goods_num)


                for a in range(len(goods[i][j][k])):


                    if(len(job_type[i][j][k])==1):
                        if(job_type[i][j][k][0]==1):
                            sub_goods_num_new_jianxiang += goods[i][j][k][a]
                        else:
                            sub_goods_num_new_zhanban += goods[i][j][k][a]
                    else:
                        r1 = goods_num[i][j][k][0]
                        if a <r1:
                            sub_goods_num_new_zhanban += goods[i][j][k][a]
                        else:
                            sub_goods_num_new_jianxiang += goods[i][j][k][a]



            if sub_job_total_jianxaing > 0:                                         #件箱数量大于0
                sub_sub_job_total.append(sub_job_total_jianxaing)
                sub_sub_job_type_total.append(1)
                sub_sub_goods_num_new.append(sub_goods_num_new_jianxiang)
            if sub_job_total_zhanban > 0:                                           #栈板数量大于0
                sub_sub_job_total.append(sub_job_total_zhanban)
                sub_sub_job_type_total.append(0)
                sub_sub_goods_num_new.append(sub_goods_num_new_zhanban)
            sub_job_total.append([sub_sub_job_total])
            sub_job_type_total.append([sub_sub_job_type_total])
            sub_job_re.append([sub_sub_job_re])
            sub_car_d_num.append([sub_sub_car_d_num])
            sub_car_d_type.append([sub_sub_car_d_type])
            sub_car_d_goods_num.append([sub_sub_car_d_goods_num])
            sub_goods_num_new.append([sub_sub_goods_num_new])


        job_total.append(sub_job_total)
        job_type_total.append(sub_job_type_total)
        job_re.append(sub_job_re)
        car_d_num.append(sub_car_d_num)
        car_d_type.append(sub_car_d_type)
        car_d_goods_num.append(sub_car_d_goods_num)
        goods_num_new.append(sub_goods_num_new)

    order_sequence.sort(key = lambda x:x[2])
    return job_total, job_type_total, job_re, goods_num_new, car_d_num, car_d_type, car_d_goods_num, no_car_re, no_job_data_re,order_sequence



def load_fun_3(job_data, job_type, n, f_p, max_c, tr, goods):
    '''
    EMS装车模型
    :param job_data: EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    :param job_type: EMS货物形态 0可代表栈板，1代表件箱，对应于EMS货物的形态，1是件箱，0是栈板，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，订单类型
    :param n: EMS的数量，用于区分EMS和自制
    :param f_p: 浮动参数，维度1，维度2 =  厂家，浮动系数
    :param max_c: 车的容量，转换为件箱的数量，维度1，维度2 =  厂家，最大容量
    :param tr: 栈板转换系数，维度1，维度2 =  厂家，转化系数
    :param goods: 栈板转换系数，维度1，维度2 =  厂家，转化系数
    :return:
    job_total:装车模型，记录每辆车装载的货物量
    car:每辆车装的货物量(乘了转化系数)，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    out_car：每辆车装的货物量(没乘转化系数)，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    car_type：装车模型的货物类型，与car相对应，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物类型
    job_re_r:记录每辆车装载的货物在job_data中的编号；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，编号；如[1,0,1,0]表示第一个厂家第零个订单第一个订单详情第零个货物
    job_re:记录每辆车装载的货物在job_data中的编号；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，编号；如[1,0,1]表示第一个厂家第零个订单第一个订单详情
    goods_num_new：每辆车装的总货物数量，相当于car_goods_d在第四个维度求和；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物数量
    job_total:每辆车装的货物量，相当于car在第四个维度求和；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    job_type_total:每辆车装的总货物类型，与car_type相关；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物类型
    car_goods_d:每辆车装的货物数量，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物数量
    '''


    car = []
    out_car = []
    job_re = []
    job_re_r = []
    car_type = []
    sub_car_type = []
    sub_job = []
    out_sub_job = []
    sub_re = []
    sub_re_r = []

    for i in range(len(job_data)):
        # 厂家层级遍历
        out_u_sub_car = []
        u_sub_car = []
        u_sub_job_re = []
        u_sub_job_re_r = []
        car_type_s = []

        for j in range(len(job_data[i])):
            # 订单层级遍历
            c = 0
            out_sub_car = []
            sub_car = []
            sub_job_re = []
            sub_job_re_r = []
            sub_sub_car_type = []
            k_num = 0
            d_num = sum(map(lambda x: len(x), job_data[i][j]))  # 得到订单的长度，为浮动处理做准备

            ch_list = []

            for k in range(len(job_data[i][j])):
                for a in range(len(job_data[i][j][k])):
                    if job_type[i][j][k][a] != 0:  # 货物为件箱
                        ch_list.append(job_data[i][j][k][a])
                    else:  # 货物为栈板，转换成件箱，方便装车模型计算
                        ch_list.append(job_data[i][j][k][a] * tr[i])
            ch_list_i = len(ch_list) - 1
            while ch_list_i > 0:
                ch_list[ch_list_i - 1] += ch_list[ch_list_i]
                ch_list_i -= 1
            for k in range(len(job_data[i][j])):
                # 订单详情层级遍历
                for a in range(len(job_data[i][j][k])):
                    # 订单详情内部遍历，订单详情可能件箱，栈板同时存在
                    k_num += 1
                    if job_type[i][j][k][a] != 0:  # 货物为件箱
                        ch = job_data[i][j][k][a]
                    else:  # 货物为栈板，转换成件箱，方便装车模型计算
                        ch = job_data[i][j][k][a] * tr[i]  # tr[i]对应着厂家的转换系数
                    if c + ch_list[k_num - 1] <= max_c[i] * (1 + f_p[i]):
                        m_c = max_c[i] * (1 + f_p[i])
                    else:
                        m_c = max_c[i]  # 不同厂家可能会用到不同类型的货车，这里找到厂家对应的货车的容量，m_c就是货车对应的容量（转化为件箱的容量后）
                    while True:
                        if c + ch <= m_c:  # c为这个车累计的容量，一开始为0，ch为订单详情内件箱的数量，或栈板转换为件箱的数量，c + ch <= m_c说明这个车可能还没装满，满足约束
                            c += ch  # 满足容量约束，累计一下货物数量
                            if job_type[i][j][k][a] == 1:  # 记录车要装载的货物数量和类型
                                out_sub_car.append(ch)
                                sub_sub_car_type.append(1)
                            else:
                                out_sub_car.append(ch // tr[i])  # 将转换后的栈板数量转化回去
                                sub_sub_car_type.append(0)
                            sub_car.append(ch)
                            sub_job_re.append([i, j, k])  # 记录订单详情的下标
                            sub_job_re_r.append([i, j, k, a])  # 记录订单详情的下标

                            if c == m_c:  # 车装满了，初始化一些变量，用来重新记录下一辆车
                                sub_job.append(sub_car)
                                out_sub_job.append(out_sub_car)
                                sub_car_type.append(sub_sub_car_type)
                                sub_re.append(sub_job_re)
                                sub_re_r.append(sub_job_re_r)
                                sub_car = []
                                out_sub_car = []
                                sub_sub_car_type = []
                                sub_job_re = []
                                sub_job_re_r = []
                                c = 0
                                break

                            if k_num == d_num:  # 到了最后一个订单详情了，需要进行订单隔离了，初始化一些变量，用来重新记录下一辆车
                                sub_job.append(sub_car)
                                out_sub_job.append(out_sub_car)
                                sub_car_type.append(sub_sub_car_type)
                                sub_re.append(sub_job_re)
                                sub_re_r.append(sub_job_re_r)
                                sub_car = []
                                out_sub_car = []
                                sub_sub_car_type = []
                                sub_job_re = []
                                sub_job_re_r = []
                                c = 0

                            break
                        elif c < m_c and c + ch > m_c:  # 当前车的容量装不下当前订单详情的货物量，需要分车来装或者浮动一下

                            if job_type[i][j][k][a] == 0:  # 货物形态为栈板
                                rr = (m_c - c) // tr[i]  # 判断剩余的容量是否能装整数个栈板
                                if rr != 0:  # 能装下一个以上的栈板
                                    out_sub_car.append(rr)
                                    sub_sub_car_type.append(0)
                                    sub_car.append(rr * tr[i])
                                    sub_job_re.append([i, j, k])
                                    sub_job_re_r.append([i, j, k, a])
                                    sub_job.append(sub_car)
                                    out_sub_job.append(out_sub_car)
                                    sub_car_type.append(sub_sub_car_type)
                                    sub_re.append(sub_job_re)
                                    sub_re_r.append(sub_job_re_r)
                                    sub_car = []
                                    out_sub_car = []
                                    sub_sub_car_type = []
                                    sub_job_re = []
                                    sub_job_re_r = []
                                    ch = ch - rr * tr[i]
                                    c = 0
                                else:  # 一个栈板都装不下
                                    c = 0
                                    out_sub_job.append(out_sub_car)
                                    sub_car_type.append(sub_sub_car_type)
                                    sub_job.append(sub_car)
                                    sub_re.append(sub_job_re)
                                    sub_re_r.append(sub_job_re_r)
                                    sub_car = []
                                    out_sub_car = []
                                    sub_sub_car_type = []
                                    sub_job_re = []
                                    sub_job_re_r = []

                            else:  # 件箱分车装
                                out_sub_car.append(m_c - c)
                                sub_sub_car_type.append(1)
                                sub_car.append(m_c - c)
                                sub_job_re.append([i, j, k])
                                sub_job_re_r.append([i, j, k, a])
                                sub_job.append(sub_car)
                                out_sub_job.append(out_sub_car)
                                sub_car_type.append(sub_sub_car_type)
                                sub_re.append(sub_job_re)
                                sub_re_r.append(sub_job_re_r)
                                sub_car = []
                                out_sub_car = []
                                sub_sub_car_type = []
                                sub_job_re = []
                                sub_job_re_r = []
                                ch = ch - (m_c - c)
                                c = 0

            u_sub_car.append(sub_job)
            out_u_sub_car.append(out_sub_job)
            car_type_s.append(sub_car_type)
            u_sub_job_re.append(sub_re)
            u_sub_job_re_r.append(sub_re_r)
            sub_car_type = []
            sub_job = []
            out_sub_job = []
            sub_re = []
            sub_re_r = []

        car.append(u_sub_car)
        car_type.append(car_type_s)
        out_car.append(out_u_sub_car)
        job_re.append(u_sub_job_re)
        job_re_r.append(u_sub_job_re_r)
    # -----------------------------------------------------------------------------------------------------------------------
    # 该段代码用于把与货物内部数量相关的列表数据合并，方便后续的遍历处理，所谓货物内部数量，就是指一个箱子，一个栈板内部的装的货物数量
    # [[[[100000.0], [500.0]]]] -> [[[100000.0, 500.0]]]
    store = []
    end_goods = []
    for i in range(len(goods)):
        sub_goods = []
        for j in range(len(goods[i])):
            for k in range(len(goods[i][j])):
                store += goods[i][j][k]
        sub_goods.append(store)
        store = []
        end_goods.append(sub_goods)
    # -----------------------------------------------------------------------------------------------------------------------
    # 该段代码用于处理时间窗求解函数的输入，即对装车模型得到的装车数据进行处理
    goods_num_new = []
    job_total = []
    job_type_total = []
    car_goods_d = []
    for i in range(len(job_re)):  # 厂家层级遍历
        job_sub = []
        type_sub = []
        ss_goods_num = []
        sub_car_goods_d = []
        num = 0
        for j in range(len(job_re[i])):  # 订单层级遍历
            sub_ss_goods_num = []
            u_job_sub = []
            u_type_sub = []
            sub_sub_car_goods_d = []
            for q in range(len(job_re[i][j])):  # 车辆层级遍历
                e = 0
                m = 0
                g_0 = 0
                g_1 = 0
                sub_sub_ss_goods_num = []
                p_type = []
                type_sub_sub = []
                job_sub_sub = []
                sub_sub_sub_car_goods_d = []
                for k in range(len(job_re[i][j][q])):  # 订单详情层级遍历
                    b_num = num
                    if job_type[job_re_r[i][j][q][k][0]][job_re_r[i][j][q][k][1]][job_re_r[i][j][q][k][2]][
                        job_re_r[i][j][q][k][3]] == 0:
                        num += int(car[i][j][q][k] / tr[i])  # 用作取货物内部数量的下标
                        m += int(car[i][j][q][k] / tr[i])  # 将一个车里的同一类货物累加起来
                        sub_sub_sub_car_goods_d.append(sum(end_goods[i][0][b_num:num]))  # 得到订单详情的货物内部数量，方便后续计算
                        g_0 += sum(end_goods[i][0][b_num:num])  # 累积同一辆车同一类型货物内部数量
                        p_type.append(0)  # 记录货物类型，方便判断
                    elif job_type[job_re_r[i][j][q][k][0]][job_re_r[i][j][q][k][1]][job_re_r[i][j][q][k][2]][
                        job_re_r[i][j][q][k][3]] == 1:
                        num += car[i][j][q][k]  # 用作取货物内部数量的下标
                        e += car[i][j][q][k]  # 将一个车里的同一类货物累加起来
                        sub_sub_sub_car_goods_d.append(sum(end_goods[i][0][b_num:num]))  # 得到订单详情的货物内部数量，方便后续计算
                        g_1 += sum(end_goods[i][0][b_num:num])  # 累积同一辆车同一类型货物内部数量
                        p_type.append(1)  # 记录货物类型，方便判断

                if 1 in p_type:
                    type_sub_sub.append(1)
                    job_sub_sub.append(e)
                    sub_sub_ss_goods_num.append(g_1)

                if 0 in p_type:
                    type_sub_sub.append(0)
                    job_sub_sub.append(m)
                    sub_sub_ss_goods_num.append(g_0)

                sub_sub_car_goods_d.append(sub_sub_sub_car_goods_d)
                u_job_sub.append(job_sub_sub)
                u_type_sub.append(type_sub_sub)
                sub_ss_goods_num.append(sub_sub_ss_goods_num)
            sub_car_goods_d.append(sub_sub_car_goods_d)
            job_sub.append(u_job_sub)
            type_sub.append(u_type_sub)
            ss_goods_num.append(sub_ss_goods_num)
        car_goods_d.append(sub_car_goods_d)
        job_total.append(job_sub)
        job_type_total.append(type_sub)
        goods_num_new.append(ss_goods_num)
    # # job_total: [[[[2], [1]]], [[[1]]], [[[2]]], [[[1]]], [[[3], [1, 1]]]]
    # [[[[3]]], [[[1]]], [[[2]]], [[[1]]], [[[3], [1, 1]]]]
    job_re = copy.deepcopy(job_re)
    return job_total, job_type_total, job_re, goods_num_new, out_car, car_type, car_goods_d


def load_se(job_data, job_type, max_c, tr, goods, car_num,t,logger):
    '''
    自制装车模型
    :param job_data: EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    :param job_type: EMS货物形态 0可代表栈板，1代表件箱，对应于EMS货物的形态，1是件箱，0是栈板，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，订单类型
    :param n: EMS的数量，用于区分EMS和自制
    :param f_p: 浮动参数，维度1，维度2 =  厂家，浮动系数
    :param max_c: 车的容量，转换为件箱的数量，维度1，维度2 =  厂家，最大容量
    :param tr: 栈板转换系数，维度1，维度2 =  厂家，转化系数
    :param goods: 栈板转换系数，维度1，维度2 =  厂家，转化系数
    :param car_num: 每个厂家的车辆数量，维度1，维度2 =  厂家，车辆数量
    :return:
    job_list:决策变量，表示某个订单详情放入该厂家的某辆车中的货物数量，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，该厂家的某辆车的货物数量
    job_total:装车模型，记录每辆车装载的货物量
    car:每辆车装的货物量(乘了转化系数)，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    out_car：每辆车装的货物量(没乘转化系数)，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    car_type：装车模型的货物类型，与car相对应，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物类型
    job_re_r:记录每辆车装载的货物在job_data中的编号；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，编号；如[1,0,1,0]表示第一个厂家第零个订单第一个订单详情第零个货物
    job_re:记录每辆车装载的货物在job_data中的编号；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，编号；如[1,0,1]表示第一个厂家第零个订单第一个订单详情
    goods_num_new：每辆车装的总货物数量，相当于car_goods_d在第四个维度求和；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物数量
    job_total:每辆车装的货物量，相当于car在第四个维度求和；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    job_type_total:每辆车装的总货物类型，与car_type相关；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物类型
    car_goods_d:每辆车装的货物数量，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物数量
    no_car_re:返回未排的订单详情标号
    no_job_data_re，返回未排的货物数量，前件箱后栈板
    '''
    no_car_re = []
    no_job_data_re = []
    # 创建CpModel实例
    model = cp_model.CpModel()

    # 入参降维准备。入参是4维矩阵，交付对象-订单-订单行-货物 分车模型不需要细到订单行，初始化空数组进行降维准备
    job_data_flatten = [[] for _ in range(len(job_data))]
    job_type_flatten = [[] for _ in range(len(job_type))]
    job_re_flatten = [[] for _ in range(len(job_data))]
    job_re_r_flatten = [[] for _ in range(len(job_data))]
    car_num_flatten = [[] for _ in range(len(car_num))]

    # 入参降维，无需实现按订单行维度分车，将订单行维度合并
    for i in range(len(job_data)):
        for j in range(len(job_data[i])):
            sub_job_data_flatten = []
            sub_job_type_flatten = []
            sub_job_re_flatten = []
            sub_job_re_r_flatten = []
            for k in range(len(job_data[i][j])):
                for a in range(len(job_data[i][j][k])):
                    sub_job_data_flatten.append(job_data[i][j][k][a])
                    sub_job_type_flatten.append(job_type[i][j][k][a])
                    sub_job_re_flatten.append([i,j,k])
                    sub_job_re_r_flatten.append([i,j,k,a])
            job_data_flatten[i].append(sub_job_data_flatten)
            job_type_flatten[i].append(sub_job_type_flatten)
            job_re_flatten[i].append(sub_job_re_flatten)
            job_re_r_flatten[i].append(sub_job_re_r_flatten)

    # 交付对象车次数量合计
    for i in range(len(car_num)):
        car_num_flatten[i]  = sum(car_num[i])

    # 建立变量列表job_list，四维数组，交付对象-订单-订单行-车次序号
    job_list = []
    # 创建每个订单每车装入货物量变量组：变量类型为int，取值范围为[0,该订单货物组数量]
    for i in range(len(job_data_flatten)):
        sub_job_list = []
        for j in range(len(job_data_flatten[i])):
            sub_sub_job_list = []
            for k in range(len(job_data_flatten[i][j])):
                sub_sub_sub_job_list = []
                for a in range(car_num_flatten[i]):
                    sub_sub_sub_job_list.append(model.NewIntVar(0, job_data_flatten[i][j][k],
                                'p_s_%d_%d_%d_%d' % (i, j, k,a)))
                sub_sub_job_list.append(sub_sub_sub_job_list)
            sub_job_list.append(sub_sub_job_list)
        job_list.append(sub_job_list)

    # 分配到该厂家所有车辆的该订单货物数量总和小于等于该货物的数量总和
    for i in range(len(job_list)):
        for j in range(len(job_list[i])):
            for k in range(len(job_list[i][j])):
                model.Add(sum(job_list[i][j][k])<=job_data_flatten[i][j][k])

    # 每辆车所装的货物数量总和不能超过该车的最大容量
    # 交付对象维度遍历决策变量job_list
    for i in range(len(job_list)):
        # j表示交付对象i的第j辆车，不存在一辆车装多个交付对象，所以按[i][0][0]遍历即可获取交付对象i的所有车次对象
        for j in range(len(job_list[i][0][0])):
            sub_job_list = []
            # 对每辆车 遍历该交付对象的所有订单和所有订单行，获取该车装的货物总量
            for k in range(len(job_list[i])):
                for a in range(len(job_list[i][k])):
                    # job_type：0栈板/1件箱；栈板货物需*板转箱系数转成箱数，计算该车装载的总箱数
                    sub_job_list.append(job_list[i][k][a][j]*(job_type_flatten[i][k][a] + (1-job_type_flatten[i][k][a])*tr[i]))
            model.Add(sum(sub_job_list) <= max_c[i])

    # 每辆车的实际装载量为分配到该车的所有订单行货物数量总和
    c_load = []
    for i in range(len(job_list)):
        sub_c_load = []
        for j in range(len(job_list[i][0][0])):
            sub_sub_c_load = []
            for k in range(len(job_list[i])):
                for a in range(len(job_list[i][k])):
                    sub_sub_c_load.append(job_list[i][k][a][j]*(job_type_flatten[i][k][a] + (1-job_type_flatten[i][k][a])*tr[i]))
            c = model.NewIntVar(0, 99999999, 'c_load_%d_%d' % (i, j))
            model.Add(sum(sub_sub_c_load) ==c)
            sub_c_load.append(c)
        c_load.append(sub_c_load)

    # 排在前序的车所装的货物数量需要大于后面的
    for i in range(len(c_load)):
        for j in range(len(c_load[i])-1):
            for k in range(j+1,len(c_load[i])):
                model.Add(c_load[i][j]>=c_load[i][k])

    # in_stock为第二次求解的决策变量，即最小化车辆数量
    in_stock = []
    # 交付对象维度遍历决策变量job_list
    for i in range(len(job_list)):
        # j表示交付对象i的第j辆车，不存在一辆车装多个交付对象，所以按[i][0][0]遍历即可获取交付对象i的所有车次对象
        for j in range(len(job_list[i][0][0])):
            sub_have_job = []
            # 对每辆车 遍历该交付对象的所有订单和所有订单行，获取该车装的货物总量
            for k in range(len(job_list[i])):
                for a in range(len(job_list[i][k])):
                    sub_have_job.append(job_list[i][k][a][j])
            # i_s标记第i个交付对象第j辆车是否被使用，即是否装有货物
            i_s = model.NewBoolVar('p_s_%d_%d' % (i,j))
            # 仅当i_s为真时，sub_have_job中所有元素的和大于0，即至少存在一个作业
            model.Add(sum(sub_have_job) >0).OnlyEnforceIf(i_s)
            model.Add(sum(sub_have_job) ==0).OnlyEnforceIf(i_s.Not())
            in_stock.append(i_s)

    # 第三次求解最小化同时装了件箱和栈板的车辆的数量，增加自制求解算法得到解的概率
    have_only_one = []
    for i in range(len(job_list)):
        for j in range(len(job_list[i][0][0])):
            have_only_piece_box = []
            have_only_pallet = []
            for k in range(len(job_list[i])):
                for a in range(len(job_list[i][k])):
                    if(job_type_flatten[i][k][a])==1:
                        have_only_piece_box.append(job_list[i][k][a][j])
                    else:
                        have_only_pallet.append(job_list[i][k][a][j])
            if len(have_only_piece_box)>0 and len(have_only_pallet)>0:

                pi = model.NewBoolVar('p_i_%d_%d' % (i,j))
                model.Add(sum(have_only_piece_box) >0).OnlyEnforceIf(pi)  #表示只有件箱
                model.Add(sum(have_only_piece_box) ==0).OnlyEnforceIf(pi.Not())

                pa = model.NewBoolVar('p_a_%d_%d' % (i,j))
                model.Add(sum(have_only_pallet) >0).OnlyEnforceIf(pa) #表示只有栈板
                model.Add(sum(have_only_pallet) ==0).OnlyEnforceIf(pa.Not())

                pipa = model.NewBoolVar('pipa_%d_%d' % (i,j))  #表示一辆车不同时出现件箱和栈板
                model.AddMultiplicationEquality(pipa, [pa, pi])
                have_only_one.append(pipa)

    # 设置不同订单不能装在一辆车约束
    for i in range(len(job_list)):
        if len(job_list[i]) >1:
            # 生成当前列表job_list[i]中所有可能的两个元素的组合
            combins = [c for c in combinations(range(len(job_list[i])), 2)]
            for c in combins:
                for j in range(len(job_list[i][c[0]])):
                    for k in range(len(job_list[i][c[1]])):
                        for a in range(car_num_flatten[i]):
                            model.AddMultiplicationEquality(0, [job_list[i][c[0]][j][a],job_list[i][c[1]][k][a]])

    # 目标函数变量obj，即所有车装入的货物总量
    obj = []
    for i in range(len(job_list)):
        for j in range(len(job_list[i])):
            for k in range(len(job_list[i][j])):
                for a in range(len(job_list[i][j][k])):
                    obj.append(job_list[i][j][k][a])

    # 定义目标函数。第一次求解要求排入的货物数量最多
    model.Maximize(sum(obj))
    # 声明求解器
    solver = cp_model.CpSolver()
    # 求解器使用8个搜索工作线程来并行搜索解决方案。可以加速求解过程，但也会增加内存使用。
    solver.parameters.num_search_workers = 8
    # 设置求解器在停止搜索之前可以花费的最大时间（单位：s）
    solver.parameters.max_time_in_seconds = t
    status = solver.Solve(model)
    # 定义目标函数。第二次求解要求使用的车次最少
    model.Add(sum(obj) == round(solver.ObjectiveValue()))
    model.Minimize(sum(in_stock))
    status2 = solver.Solve(model)
    # 第三次求解要求件箱和栈板分开来，效率原因不再启用
    # model.Add(sum(in_stock) == round(solver.ObjectiveValue()))
    # model.Minimize(sum(have_only_one))
    # status3 = solver.Solve(model)
    status3 = 4
    # 得到最终的解
    if status == cp_model.OPTIMAL and status2 == cp_model.OPTIMAL and status3==cp_model.OPTIMAL:
        logger.info("自制装车模型求得最优解")
    elif (status == cp_model.FEASIBLE or status == cp_model.OPTIMAL) and (status2 == cp_model.FEASIBLE or status2 == cp_model.OPTIMAL) and (status3 == cp_model.FEASIBLE or status3 == cp_model.OPTIMAL):
        logger.info("自制装车模型求得次优解")
    else :
        logger.error("自制装车模型无解，程序结束")
        exit()

    solution = []
    for i in range(len(job_list)):
        sub_job_list = []
        for j in range(len(job_list[i])):
            sub_sub_job_list = []
            for k in range(len(job_list[i][j])):
                sub_sub_sub_job_list = []
                for a in range(len(job_list[i][j][k])):
                    sub_sub_sub_job_list.append(solver.Value(job_list[i][j][k][a]))
                sb = sum(sub_sub_sub_job_list)
                if sb < job_data_flatten[i][j][k]:
                    no_car_re.append(copy.deepcopy(job_re_flatten[i][j][k]))
                    no_job_data_re.append(copy.deepcopy([job_type_flatten[i][j][k] * (job_data_flatten[i][j][k]- sb), (1 - job_type_flatten[i][j][k]) *( job_data_flatten[i][j][k]- sb)]))
                sub_sub_job_list.append(sb)
            sub_job_list.append(sub_sub_job_list)
        solution.append(sub_job_list)

    car = []
    car_type = []
    out_car = []
    job_re = []
    job_re_r = []
    for i in range(len(job_list)):
        sub_car = []
        sub_car_type = []
        sub_out_car = []
        sub_job_re = []
        sub_job_re_r = []
        for j in range(len(job_list[i])):
            sub_sub_car = []
            sub_sub_car_type = []
            sub_sub_out_car = []
            sub_sub_job_re = []
            sub_sub_job_re_r = []
            for k in range(len(job_list[i][j][0])):
                sub_sub_sub_car = []
                sub_sub_sub_car_type = []
                sub_sub_sub_out_car = []
                sub_sub_sub_job_re = []
                sub_sub_sub_job_re_r = []
                for a in range(len(job_list[i][j])):
                    if solver.Value(job_list[i][j][a][k]) >0:
                        sub_sub_sub_car.append(solver.Value(job_list[i][j][a][k])*(job_type_flatten[i][j][a] + (1-job_type_flatten[i][j][a])*tr[i])) #转换后的数据
                        sub_sub_sub_car_type.append(job_type_flatten[i][j][a])
                        sub_sub_sub_out_car.append(solver.Value(job_list[i][j][a][k]))
                        sub_sub_sub_job_re.append(copy.deepcopy(job_re_flatten[i][j][a]))
                        sub_sub_sub_job_re_r.append(copy.deepcopy(job_re_r_flatten[i][j][a]))
                if sum(sub_sub_sub_car) >0:
                    sub_sub_car.append(sub_sub_sub_car)
                    sub_sub_car_type.append(sub_sub_sub_car_type)
                    sub_sub_out_car.append(sub_sub_sub_out_car)
                    sub_sub_job_re.append(sub_sub_sub_job_re)
                    sub_sub_job_re_r.append(sub_sub_sub_job_re_r)
            sub_car.append(sub_sub_car)
            sub_car_type.append(sub_sub_car_type)
            sub_out_car.append(sub_sub_out_car)
            sub_job_re.append(sub_sub_job_re)
            sub_job_re_r.append(sub_sub_job_re_r)
        car.append(sub_car)
        car_type.append(sub_car_type)
        out_car.append(sub_out_car)
        job_re.append(sub_job_re)
        job_re_r.append(sub_job_re_r)



    store = []
    end_goods = []
    for i in range(len(goods)):
        sub_goods = []
        for j in range(len(goods[i])):
            for k in range(len(goods[i][j])):
                store += goods[i][j][k]
        sub_goods.append(store)
        store = []
        end_goods.append(sub_goods)


    ends_good_num = []
    for i in range(len(job_data)):
        sub_ends_good_num = []
        for j in range(len(job_data[i])):
            sub_sub_ends_good_num = []
            for k in range(len(job_data[i][j])):
                # sub_sub_sub_ends_good_num = [0]
                # for a in range(len(job_data[i][j][k])):
                #     sub_sub_sub_ends_good_num.append(0)
                sub_sub_ends_good_num.append(0)
            sub_ends_good_num.append(sub_sub_ends_good_num)
        ends_good_num.append(sub_ends_good_num)
    # -----------------------------------------------------------------------------------------------------------------------
    # 该段代码用于处理时间窗求解函数的输入，即对装车模型得到的装车数据进行处理

    goods_num_new = []
    job_total = []
    job_type_total = []
    car_goods_d = []
    for i in range(len(job_re)):  # 厂家层级遍历
        job_sub = []
        type_sub = []
        ss_goods_num = []
        sub_car_goods_d = []
        num = 0
        for j in range(len(job_re[i])):  # 订单层级遍历
            sub_ss_goods_num = []
            u_job_sub = []
            u_type_sub = []
            sub_sub_car_goods_d = []
            for q in range(len(job_re[i][j])):  # 车辆层级遍历
                e = 0
                m = 0
                g_0 = 0
                g_1 = 0
                sub_sub_ss_goods_num = []
                p_type = []
                type_sub_sub = []
                job_sub_sub = []
                sub_sub_sub_car_goods_d = []
                for k in range(len(job_re[i][j][q])):  # 订单详情层级遍历
                    if job_type[job_re_r[i][j][q][k][0]][job_re_r[i][j][q][k][1]][job_re_r[i][j][q][k][2]][
                        job_re_r[i][j][q][k][3]] == 0:

                        num = int(car[i][j][q][k] / tr[i])
                        b_num = ends_good_num[job_re[i][j][q][k][0]][job_re[i][j][q][k][1]][job_re[i][j][q][k][2]]
                        m += int(car[i][j][q][k] / tr[i])  # 将一个车里的同一类货物累加起来
                        sub_sub_sub_car_goods_d.append(sum(goods[job_re[i][j][q][k][0]][job_re[i][j][q][k][1]][job_re[i][j][q][k][2]][b_num:b_num + num]))  # 得到订单详情的货物内部数量，方便后续计算
                        g_0 += sum(goods[job_re[i][j][q][k][0]][job_re[i][j][q][k][1]][job_re[i][j][q][k][2]][b_num:b_num + num])  # 累积同一辆车同一类型货物内部数量
                        p_type.append(0)  # 记录货物类型，方便判断
                        ends_good_num[job_re[i][j][q][k][0]][job_re[i][j][q][k][1]][job_re[i][j][q][k][2]] += num
                    elif job_type[job_re_r[i][j][q][k][0]][job_re_r[i][j][q][k][1]][job_re_r[i][j][q][k][2]][
                        job_re_r[i][j][q][k][3]] == 1:

                        num = car[i][j][q][k]  # 用作取货物内部数量的下标
                        b_num = ends_good_num[job_re[i][j][q][k][0]][job_re[i][j][q][k][1]][job_re[i][j][q][k][2]]
                        e += car[i][j][q][k]  # 将一个车里的同一类货物累加起来
                        sub_sub_sub_car_goods_d.append(sum(goods[job_re[i][j][q][k][0]][job_re[i][j][q][k][1]][job_re[i][j][q][k][2]][b_num:b_num + num]))  # 得到订单详情的货物内部数量，方便后续计算
                        g_1 += sum(goods[job_re[i][j][q][k][0]][job_re[i][j][q][k][1]][job_re[i][j][q][k][2]][b_num:b_num + num])  # 累积同一辆车同一类型货物内部数量
                        p_type.append(1)  # 记录货物类型，方便判断
                        ends_good_num[job_re[i][j][q][k][0]][job_re[i][j][q][k][1]][job_re[i][j][q][k][2]] += num
                if 1 in p_type:
                    type_sub_sub.append(1)
                    job_sub_sub.append(e)
                    sub_sub_ss_goods_num.append(g_1)

                if 0 in p_type:
                    type_sub_sub.append(0)
                    job_sub_sub.append(m)
                    sub_sub_ss_goods_num.append(g_0)

                sub_sub_car_goods_d.append(sub_sub_sub_car_goods_d)
                u_job_sub.append(job_sub_sub)
                u_type_sub.append(type_sub_sub)
                sub_ss_goods_num.append(sub_sub_ss_goods_num)
            sub_car_goods_d.append(sub_sub_car_goods_d)
            job_sub.append(u_job_sub)
            type_sub.append(u_type_sub)
            ss_goods_num.append(sub_ss_goods_num)
        car_goods_d.append(sub_car_goods_d)
        job_total.append(job_sub)
        job_type_total.append(type_sub)
        goods_num_new.append(ss_goods_num)


    no_car_re_temp = []
    no_car_type_temp = []
    no_out_car_temp = []



    for i in range(len(job_total)): #若所排的车辆数量大于给定数量则删除
        total_car_num = sum(car_num[i])
        car_num_check = 0
        for j in range(len(job_total[i])):
            for k in range(len(job_total[i][j])):
                if car_num_check < total_car_num:
                    car_num_check += 1
                else:
                    no_car_re_temp += job_re[i][j][k:len(job_re[i][j])]
                    no_out_car_temp += out_car[i][j][k:len(out_car[i][j])]
                    no_car_type_temp += car_type[i][j][k:len(car_type[i][j])]
                    del job_total[i][j][k:len(job_total[i][j])]
                    del job_type_total[i][j][k:len(job_type_total[i][j])]
                    del job_re[i][j][k:len(job_re[i][j])]
                    del goods_num_new[i][j][k:len(goods_num_new[i][j])]
                    del out_car[i][j][k:len(out_car[i][j])]
                    del car_type[i][j][k:len(car_type[i][j])]
                    del car_goods_d[i][j][k:len(car_goods_d[i][j])]
                    break

    no_car_re_temp = sum(no_car_re_temp, [])
    no_car_type_temp = sum(no_car_type_temp, [])
    no_out_car_temp = sum(no_out_car_temp, [])

    no_job_data_re_temp = [[no_car_type_temp[i] * no_out_car_temp[i], (1 - no_car_type_temp[i]) * no_out_car_temp[i]]
                           for i in range(len(no_car_re_temp))] #前件箱后栈板


    if no_car_re_temp != []: #返回未排的货物数据
        slow = 0
        temp = no_job_data_re_temp[0]
        for i in range(1, len(no_car_re_temp)):
            if no_car_re_temp[i] != no_car_re_temp[slow]:
                no_job_data_re.append(temp)
                no_car_re.append(no_car_re_temp[slow])
                temp = [0, 0]
                slow = i

            temp[0] += no_job_data_re_temp[i][0]
            temp[1] += no_job_data_re_temp[i][1]
        no_job_data_re.append(temp)
        no_car_re.append(no_car_re_temp[slow])



    return job_total, job_type_total, job_re, goods_num_new, out_car, car_type, car_goods_d, no_car_re, no_job_data_re

def zz_process(job_total, job_type_total, job_re, goods_num_new, out_car, car_type, car_goods_d, car_num):
    # 处理自制缺车的数据
    re = []

    for i in range(len(job_total)):
        total_car_num = sum(car_num[i])
        car_num_check = 0
        for j in range(len(job_total[i])):
            for k in range(len(job_total[i][j])):
                if car_num_check < total_car_num:
                    car_num_check += 1
                else:
                    del job_total[i][j][k:len(job_total[i][j])]
                    del job_type_total[i][j][k:len(job_type_total[i][j])]
                    re += job_re[i][j][k:len(job_re[i][j])][0]
                    del job_re[i][j][k:len(job_re[i][j])]
                    del goods_num_new[i][j][k:len(goods_num_new[i][j])]
                    del out_car[i][j][k:len(out_car[i][j])]
                    del car_type[i][j][k:len(car_type[i][j])]
                    del car_goods_d[i][j][k:len(car_goods_d[i][j])]
                    break

    return job_total, job_type_total, job_re, goods_num_new, out_car, car_type, car_goods_d, re

def insert_sort_zz_time(zz_time_begin, zz_time_end, car_num,time_window,insert_time):
    '''
    自制车辆优先级预处理，后续算法会优先选择发车时间在时间窗内的车
    :param zz_time_begin    自制开始时间
    :param zz_time_end      自制结束时间
    :param car_num          车辆数量
    :param time_window      时间窗
    :param insert_time      插入时间
    :return new_car_num     更新后的车辆数量
    :return new_zz_time_begin   更新后的开始时间
    :return new_zz_time_end     更新后的结束时间
    '''
    new_zz_time_begin, new_zz_time_end, new_car_num = [[]for _ in range(len(zz_time_begin))],[[]for _ in range(len(zz_time_end))],[[]for _ in range(len(car_num))]

    for i in range(len(zz_time_begin)):
        IND = [(idx,num) for idx,num in enumerate(zz_time_begin[i])]   #给每个开始时间一个序号
        IND = sorted(IND,key=lambda x: x[1])            #对开始时间排序
        before = []
        last = []
        for j in range(len(IND)):                      #遍历开始时间
            if IND[j][1]>=insert_time:                 #判断开始时间大于等于插入时间
                flag_bl = False
                for q in range(len(time_window)):       #判断开始时间是否在时间窗内部
                    if IND[j][1]>= time_window[q][0] and zz_time_end[i][IND[j][0]] <= time_window[q][1]:
                        flag_bl = True
                        break
                if IND[j][1] ==  zz_time_end[i][IND[j][0]]:     #
                    flag_bl = False
                if  flag_bl == True:                    #如果开始时间在时间窗内且晚于插单时间，则加入before数组
                    before.append(copy.deepcopy(IND[j][0]))
                else:                                   #如果开始时间不在时间窗内，则加入before数组
                    last.append(copy.deepcopy(IND[j][0]))
            else:                                       #如果开始时间早于插单时间，则加入before数组
                last.append(copy.deepcopy(IND[j][0]))
        for k in range(len(before)):                #按照先before后last的顺序查找索引把数值填入车辆数量、开始时、结束时间中
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][before[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][before[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][before[k]]))
        for k in range(len(last)):
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][last[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][last[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][last[k]]))


    return new_car_num,new_zz_time_begin,new_zz_time_end

def sort_zz_time(zz_time_begin, zz_time_end, car_num,time_window):
    '''
    自制车辆优先级预处理，后续算法会优先选择发车时间在时间窗内的车
    :param zz_time_begin    自制开始时间
    :param zz_time_end      自制结束时间
    :param car_num          车辆数量
    :param time_window      时间窗
    :param insert_time      插入时间
    :return new_car_num     更新后的车辆数量
    :return new_zz_time_begin   更新后的开始时间
    :return new_zz_time_end     更新后的结束时间
    '''
    new_zz_time_begin, new_zz_time_end, new_car_num = [[]for _ in range(len(zz_time_begin))],[[]for _ in range(len(zz_time_end))],[[]for _ in range(len(car_num))]
    for i in range(len(zz_time_begin)):
        IND = [(idx,num) for idx,num in enumerate(zz_time_begin[i])]    #给每个开始时间一个序号
        IND = sorted(IND,key=lambda x: x[1])     #对开始时间排序
        before = []
        last = []
        for j in range(len(IND)):            #遍历开始时间
            flag_bl = False
            for q in range(len(time_window)): #判断开始时间是否在时间窗内部
                if IND[j][1]>= time_window[q][0] and zz_time_end[i][IND[j][0]] <= time_window[q][1]:
                    flag_bl = True
                    break
            if  flag_bl == True:    #如果开始时间在时间窗内，则加入before数组
                before.append(copy.deepcopy(IND[j][0]))
            else:               #如果开始时间不在时间窗内，则加入before数组
                last.append(copy.deepcopy(IND[j][0]))

        for k in range(len(before)):    #按照先before后last的顺序查找索引把数值填入车辆数量、开始时、结束时间中
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][before[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][before[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][before[k]]))
        for k in range(len(last)):
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][last[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][last[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][last[k]]))

    return new_car_num,new_zz_time_begin,new_zz_time_end

def insert_get_se_car_to_time(zz_car, zz_time_begin, zz_time_end, car_num,insert_time):
    '''
    该函数就是把处理后的自制发车表时间分配给排的自制车，在功能的实现上和get_se_car_to_time_before是一样的，但是得到的时间是经过time_window_process_se处理过的
    :param zz_car: 自制根据货物排的车
    :param zz_time_begin: 自制发车表的开始时间
    :param zz_time_end: 自制发车表的结束时间
    :param car_num: 自制发车表对应的车
    :return: car_time：得到自制排好的车对应的时间
    '''

    new_zz_time_begin, new_zz_time_end, new_car_num = [[]for _ in range(len(zz_time_begin))],[[]for _ in range(len(zz_time_end))],[[]for _ in range(len(car_num))]


    for i in range(len(zz_time_begin)):
        IND = [(idx,num) for idx,num in enumerate(zz_time_begin[i])]
        IND = sorted(IND,key=lambda x: x[1])
        before = []
        last = []
        for j in range(len(IND)):
            if IND[j][1]>insert_time:
                before.append(copy.deepcopy(IND[j][0]))
            else:
                last.append(copy.deepcopy(IND[j][0]))
        for k in range(len(before)):
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][before[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][before[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][before[k]]))
        for k in range(len(last)):
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][last[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][last[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][last[k]]))

        for j in range(len(IND)):
            last.append(copy.deepcopy(IND[j][0]))
        for k in range(len(last)):
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][last[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][last[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][last[k]]))

    car_index = []
    car_to_time = []
    for i in range(len(new_car_num)):
        sub_car_to_time = []
        sub_car_index = []
        car_num_re = 0
        for j in range(len(new_car_num[i])):
            car_num_re += new_car_num[i][j]
            sub_car_index.append(car_num_re)
            sub_car_to_time.append([new_zz_time_begin[i][j], new_zz_time_end[i][j]])
        car_to_time.append(sub_car_to_time)
        car_index.append(sub_car_index)

    car_time = []
    for i in range(len(zz_car)):
        car_time_sub = []
        index_num = 0
        zz_car_num = 0
        for j in range(len(zz_car[i])):
            car_time_sub_sub = []
            for k in range(len(zz_car[i][j])):
                if zz_car_num == car_index[i][index_num]:
                    index_num += 1
                car_time_sub_sub.append(car_to_time[i][index_num])
                zz_car_num += 1
            car_time_sub.append(car_time_sub_sub)
        car_time.append(car_time_sub)

    return car_time

def get_se_car_to_time(zz_car, zz_time_begin, zz_time_end, car_num):
    '''
    该函数就是把处理后的自制发车表时间分配给排的自制车，在功能的实现上和get_se_car_to_time_before是一样的，但是得到的时间是经过time_window_process_se处理过的
    :param zz_car: 自制根据货物排的车
    :param zz_time_begin: 自制发车表的开始时间
    :param zz_time_end: 自制发车表的结束时间
    :param car_num: 自制发车表对应的车
    :return: car_time：得到自制排好的车对应的时间
    '''

    car_index = []
    car_to_time = []
    for i in range(len(car_num)):
        sub_car_to_time = []
        sub_car_index = []
        car_num_re = 0
        for j in range(len(car_num[i])):
            car_num_re += car_num[i][j]
            sub_car_index.append(car_num_re)
            sub_car_to_time.append([zz_time_begin[i][j], zz_time_end[i][j]])
        car_to_time.append(sub_car_to_time)
        car_index.append(sub_car_index)

    car_time = []
    for i in range(len(zz_car)):
        car_time_sub = []
        index_num = 0
        zz_car_num = 0
        for j in range(len(zz_car[i])):
            car_time_sub_sub = []
            for k in range(len(zz_car[i][j])):
                if zz_car_num == car_index[i][index_num]:
                    index_num += 1
                car_time_sub_sub.append(car_to_time[i][index_num])
                zz_car_num += 1
            car_time_sub.append(car_time_sub_sub)
        car_time.append(car_time_sub)

    return car_time


def insert_get_se_car_to_time_before(zz_car, zz_time_begin, zz_time_end, car_num,insert_time):
    '''
    该函数用于得到还未经time_window_process_se函数处理过的自制发车时间，主要作用就是给排的自制车分配发车的开始时间和结束时间，然后方便get_end_zz_time函数的使用
    :param zz_car: 自制根据货物排的车
    :param zz_time_begin: 自制发车表的开始时间
    :param zz_time_end: 自制发车表的结束时间
    :param car_num: 自制发车表对应的车
    :return: car_time：得到自制排好的车对应的时间
    '''

    new_zz_time_begin, new_zz_time_end, new_car_num = [[]for _ in range(len(zz_time_begin))],[[]for _ in range(len(zz_time_end))],[[]for _ in range(len(car_num))]


    for i in range(len(zz_time_begin)):
        IND = [(idx,num) for idx,num in enumerate(zz_time_begin[i])]         #给每个开始时间一个序号
        IND = sorted(IND,key=lambda x: x[1])               #对开始时间排序
        before = []
        last = []
        for j in range(len(IND)):                   #遍历开始时间
            if IND[j][1]>insert_time:                #判断开始时间大于等于插入时间
                before.append(copy.deepcopy(IND[j][0]))
            else:
                last.append(copy.deepcopy(IND[j][0]))
        for k in range(len(before)):            #按照先before后last的顺序查找索引把数值填入车辆数量、开始时、结束时间中
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][before[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][before[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][before[k]]))
        for k in range(len(last)):
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][last[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][last[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][last[k]]))

        for j in range(len(IND)):
            last.append(copy.deepcopy(IND[j][0]))
        for k in range(len(last)):
            new_zz_time_begin[i].append(copy.deepcopy(zz_time_begin[i][last[k]]))
            new_zz_time_end[i].append(copy.deepcopy(zz_time_end[i][last[k]]))
            new_car_num[i].append(copy.deepcopy(car_num[i][last[k]]))

    car_index = []
    car_to_time = []
    for i in range(len(new_car_num)):       #厂家层级遍历
        sub_car_to_time = []
        sub_car_index = []
        car_num_re = 0
        for j in range(len(new_car_num[i])):
            car_num_re += new_car_num[i][j]         #累加
            sub_car_index.append(car_num_re)
            sub_car_to_time.append([new_zz_time_begin[i][j], new_zz_time_end[i][j]])
        car_to_time.append(sub_car_to_time)             #添加自制的时间
        car_index.append(sub_car_index)                 #添加车的索引号

    car_time = []
    for i in range(len(zz_car)):
        car_time_sub = []
        index_num = 0
        zz_car_num = 0
        for j in range(len(zz_car[i])):
            car_time_sub_sub = []
            for k in range(len(zz_car[i][j])):
                if zz_car_num == car_index[i][index_num]:
                    index_num += 1
                car_time_sub_sub.append(car_to_time[i][index_num])
                zz_car_num += 1
            car_time_sub.append(car_time_sub_sub)
        car_time.append(car_time_sub)

    return car_time

def get_se_car_to_time_before(zz_car, zz_time_begin, zz_time_end, car_num):
    '''
    该函数用于得到还未经time_window_process_se函数处理过的自制发车时间，主要作用就是给排的自制车分配发车的开始时间和结束时间，然后方便get_end_zz_time函数的使用
    :param zz_car: 自制根据货物排的车
    :param zz_time_begin: 自制发车表的开始时间
    :param zz_time_end: 自制发车表的结束时间
    :param car_num: 自制发车表对应的车
    :return: car_time：得到自制排好的车对应的时间
    '''

    car_index = []
    car_to_time = []
    for i in range(len(car_num)):
        sub_car_to_time = []
        sub_car_index = []
        car_num_re = 0
        for j in range(len(car_num[i])):
            car_num_re += car_num[i][j]
            sub_car_index.append(car_num_re)
            sub_car_to_time.append([zz_time_begin[i][j], zz_time_end[i][j]])
        car_to_time.append(sub_car_to_time)
        car_index.append(sub_car_index)

    car_time = []
    for i in range(len(zz_car)):
        car_time_sub = []
        index_num = 0
        zz_car_num = 0
        for j in range(len(zz_car[i])):
            car_time_sub_sub = []
            for k in range(len(zz_car[i][j])):
                if zz_car_num == car_index[i][index_num]:
                    index_num += 1
                car_time_sub_sub.append(car_to_time[i][index_num])
                zz_car_num += 1
            car_time_sub.append(car_time_sub_sub)
        car_time.append(car_time_sub)

    return car_time

def \
        se_solve(job_data, job_type, data_end_start, V_j, c, a_c, dis, zz_car_time, V_EMS_j, t, zz_interval_time, ems_c,
             rong_liang_zz, zhuan_hua_zz, box_flow_value, zz_delivery_count, ems_delivery_count, zz_priority, max_time,random_index,random_ems_index, random_zz_index,floor_speed_map,portEmsLpnNum3,portEmsLpnNum2,portSelfLpnNum2,order_sequence,is_splitting_car,floor_port_num_map,ems_floor,zz_floor,port_assignment_map,logger):
    """
    该函数用于求解时间窗，输入输出参数解释如下
    :param job_data:EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列；维度1,维度2,维度3,维度4 = 厂家,订单,车辆，货物数量
    :param d_list:EMS货物的截止日期
    :param job_type:EMS货物形态 0可代表栈板，1代表件箱，2代表gtp；维度1,维度2,维度3,维度4 = 厂家,订单,车辆，货物类型
    :param data_end_start:各个任务对应的开始时间
    :param V_j: 不同类型货物对应通道的速度，数量/秒，[栈板速度，自制速度，件箱速度]
    :param c:对应于自制的可用通道；维度1，维度2，维度3 =  厂家，订单，货物类型，通道类型和数量；[0,1]表示1楼，[1,0]表示-1楼； 第三个维度前件箱，后栈板；如 s_c = [[[[1, 0, 1, 0], [1, 1, 1]]], [[[0, 1], [1, 1, 1]]]]表示第一个厂家安排了负1楼件箱通道2个,栈板通道3个;第二个厂家安排了1楼件箱通道1个,栈板通道3个
    :param a_c:栈板的总通道数量
    :param t:求解时间，若最后无解，则需调大时间
    :param dis:打折系数
    :param V_EMS_j:输入到EMS求解的速度参数,单位:数量/秒，[栈板速度，件箱速度，自制速度]
    :param zz_car_time: 每辆车的开始和结束时间 维度1,维度2,维度3,维度4 = 厂家,订单,车辆，时间
    :param zz_interval_time:自制发车间隔时间
    :param c:对应于EMS的可用通道；维度1，维度2，维度3，维度4 = 厂家，订单，通道类型，通道 ；通道类型中前一个维度都是件箱的，后一个维度都是栈板的，如c = [[[[1, 1, 1, 1], [1, 1]]]]中[1, 1, 1, 1]表示件箱可用的通道，[1,1]表示栈板可用的通道
    :param rong_liang_zz:对应于厂家的车辆容量，只有一个维度(自制)
    :param zhuan_hua_zz:对应于厂家的转换系数，只有一个维度(自制)
    :param box_flow_value:最大流量限制
    :param zz_delivery_count:最大自制通道限制
    :param ems_delivery_count:最大ems通道限制
    :param max_time:归一化后所有时间戳相关参数的最大时间
    :return: solution_x_total 所有子任务的开始处理时间和处理结束时间，单位为秒，维度1,维度2,维度3,维度4 = 厂家,订单,车辆，时间
    solution_bool_sub_job 该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理；维度1,维度2,维度3,维度4 = 厂家,订单,车辆，是否被处理
    solution_bool_C 该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用；维度1,维度2,维度3,维度4 = 厂家,订单,车辆，通道号
    solution_bool_C_N 方便EMS求解使用的通道参数；维度1,维度2,维度3,维度4 = 厂家,订单,车辆，通道号
    total_C_list:货物是否被安排在某个通道中
    j_sub_p_s:某个货物在时间窗内的开始时间
    j_sub_p_e:某个货物在时间窗内的结束时间
    j_sub_p_e_1：某个货物在时间窗内的时间间隔
    """

    # # 对速度进行折扣处理
    # for v in range(len(V_j)):
    #     if int(V_j[v] * dis) != 0:
    #         V_j[v] = int(V_j[v] * dis)
    #     else:
    #         V_j[v] = 1
    # # 对速度进行折扣处理
    # for v in range(len(V_EMS_j)):
    #     if int(V_EMS_j[v] * dis) != 0:
    #         V_EMS_j[v] = int(V_EMS_j[v] * dis)
    #     else:
    #         V_EMS_j[v] = 1

    if (is_splitting_car==False):
        max_time = 999999999
    total_zz_cargo_num,total_ems_cargo_num = get_zz_cargo_num(job_data,job_type,c)
    total_cargo_num = get_cargo_num_(job_data,job_type)

    # 对速度进行折扣处理
    floor_speed_map_integer = {}
    for v in floor_speed_map:
        floor_speed_map_integer[v] = int(floor_speed_map[v] * dis * 10000)#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    # 对速度进行折扣处理
    # for v in range(len(V_EMS_j)):
    #     V_EMS_j[v] = int(V_EMS_j[v] * dis * 10000)#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度
    for v in range(len(V_j)):
        V_j[v] = int(V_j[v] * dis * 10000)#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    # 对速度进行折扣处理
    for v in range(len(V_EMS_j)):
        V_EMS_j[v] = int(V_EMS_j[v] * dis * 10000)#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    total_C_list = []
    bool_job_list = []
    bool_sub_job_list = []
    job_p_list = []
    x_intervals = []
    y_intervals = []
    solution_x_total = []
    solution_bool_sub_job = []
    solution_bool_C = []
    solution_bool_C_N = []
    de = []
    min_end_time = []
    rs_c = []
    rs_zz_delivery_count = []
    rs_ems_delivery_count = []
    total_bb = 0
    total_bbb = 0

    model = cp_model.CpModel()

    for i in range(len(job_data)):  # 厂家层级遍历
        j_b = model.NewBoolVar('%d' % i)  # 该厂家的车是否全部排完
        total_bb += j_b
        bool_job_list.append(j_b)
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        bool_sub_ssub_job = []

        c_num_occupy = {}
        for port_num in floor_port_num_map:
            c_num_occupy[port_num] = [[] for _ in range(floor_port_num_map[port_num])]
        c_occupy_s = {}
        for j,port_num in enumerate(floor_port_num_map):
            c_occupy_s[port_num] = [model.NewIntVar(0, 100, 'p_e_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]
        c_occupy = {}
        for j,port_num in enumerate(floor_port_num_map) :
            c_occupy[port_num] = [model.NewBoolVar('ocp_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]

        # ems_c_num_occupy = [[] for _ in range(len(random_ems_index))]
        # zz_c_num_occupy = [[] for _ in range(len(random_zz_index))]
        # ems_c_occupy_s = [model.NewIntVar(0, 100, 'p_e_%d' % (i)) for i in range(len(random_ems_index))]
        # zz_c_occupy_s = [model.NewIntVar(0, 100, 'p_e_%d' % (i)) for i in range(len(random_zz_index))]
        # ems_c_occupy = [model.NewBoolVar('ocp_%d' % (i)) for i in range(len(random_ems_index))]
        # zz_c_occupy = [model.NewBoolVar('ocp_%d' % (i)) for i in range(len(random_zz_index))]
        for j in range(len(job_data[i])):  # 订单层级的遍历
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))  # 订单是否完成
            bool_sub_job.append(j_sub_b)
            u_bool_sub_sub_job = []
            u_job_p_sub_sub = []
            u_sub_C_list = []
            u_bool_sub_job_se = []


            for k in range(len(job_data[i][j])):  # 车辆层级遍历
                u_j_sub_b_se = model.NewBoolVar('%d_%d_%d' % (i, j, k))  # 车辆是否排入
                u_bool_sub_job_se.append(u_j_sub_b_se)
                bool_sub_sub_job = []
                job_p_sub_sub = []
                sub_C_list = []
                for p in range(len(job_data[i][j][k])):  # 车内部货物类型层级遍历（件箱、栈板）
                    j_sub_sub_b = model.NewBoolVar('%d_%d_%d_%d' % (i, j, k, p))  # 货物是否被分配通道并在交期内处理
                    bool_sub_sub_job.append(j_sub_sub_b)
                    total_bbb += j_sub_sub_b
                    sub_sub_c_list = []
                    sub_sub_p_list = []
                    j_sub_p_s = model.NewIntVar(zz_car_time[i][j][k][0], max_time,
                                                'p_s_%d_%d_%d_%d' % (i, j, k, p))  # 货物开始处理时间变量
                    j_sub_p_e = model.NewIntVar(zz_car_time[i][j][k][0], max_time,
                                                'p_e_%d_%d_%d_%d' % (i, j, k, p))  # 货物结束处理时间变量
                    j_sub_p_e_1 = model.NewIntVar(zz_car_time[i][j][k][0], max_time,
                                                  'p_e1_%d_%d_%d_%d' % (i, j, k, p))  # 用于车辆时间间隔的变量
                    min_end_time.append(j_sub_p_e)
                    due_data_d = model.NewBoolVar('due_data_d')  # 交期是否满足的变量
                    c_d = model.NewBoolVar('c_d')  # 是否分配通道的变量
                    model.Add(j_sub_p_e <= zz_car_time[i][j][k][1]).OnlyEnforceIf(due_data_d)  # 交期约束
                    model.Add(j_sub_p_e > zz_car_time[i][j][k][1]).OnlyEnforceIf(due_data_d.Not())  # 交期约束
                    sub_sub_p_list.append(j_sub_p_s)
                    sub_sub_p_list.append(j_sub_p_e)
                    sub_sub_p_list.append(j_sub_p_e_1)
                    job_p_sub_sub.append(sub_sub_p_list)

                    # if job_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                    #     for v in range(len(c[i][j][1])):  # 遍历通道
                    #         if c[i][j][1][v] == 1:  # 通道可以使用，为0则是被禁用
                    #             b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, 7))
                    #             sub_sub_c_list.append(b)


                    if job_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                        for v in range(floor_port_num_map['plt']):  # 遍历通道
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, 7))
                            sub_sub_c_list.append(b)
                    else:
                        # # 自制件箱的通道有些特殊，自制的通道分为去一楼的和去负一楼的，一楼的通道坏了，现在和EMS的通道共享
                        # if c[i][j][0][0] == 1:  # 去负一楼的通道，不用和EMS共享
                        #     for m in range(len(c[i][j][0])):
                        #         if c[i][j][0][m] == 1:
                        #             b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                        #             sub_sub_c_list.append(b)
                        #             zz_c_num_occupy[m//2].append(b)
                        # else:  # 去一楼的，得和EMS共享
                        #     # cc = [1, 1, 1, 1, 1, 1, 1]
                        #     cc = ems_c[0][0][0]
                        #     for m in range(len(cc)):
                        #         if cc[m] == 1:
                        #             b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                        #             sub_sub_c_list.append(b)
                        #             ems_c_num_occupy[m].append(b)

                        for m in range(floor_port_num_map[zz_floor[i]]):
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                            sub_sub_c_list.append(b)
                            c_num_occupy[zz_floor[i]][m].append(b)


                    model.Add(sum(sub_sub_c_list) <= job_data[i][j][k][p])
                    model.Add(sum(sub_sub_c_list) > 0).OnlyEnforceIf(c_d)  # 分配通道，c_d为1
                    model.Add(sum(sub_sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
                    # model.Add(due_data_d == 1).OnlyEnforceIf(c_d)
                    model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_sub_b)  # 交期通道两个全满足，货物进去
                    model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_sub_b.Not())
                    sub_C_list.append(sub_sub_c_list)
                u_job_p_sub_sub.append(job_p_sub_sub)
                u_sub_C_list.append(sub_C_list)
                u_bool_sub_sub_job.append(bool_sub_sub_job)
                model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(
                    u_j_sub_b_se)  # 件箱和栈板全部排入或件箱、栈板排入就代表车排入了
                model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(u_j_sub_b_se.Not())



            model.Add(sum(u_bool_sub_job_se) == len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b)  # 车全排入了，就代表订单完成了
            model.Add(sum(u_bool_sub_job_se) < len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b.Not())

            C_list.append(u_sub_C_list)
            bool_sub_ssub_job.append(u_bool_sub_sub_job)
            job_p_sub.append(u_job_p_sub_sub)


        # if c[i][0][0][0] == 0:
        #     if total_ems_cargo_num[i] >0:
        #         [model.Add(ems_c_occupy_s[v] == sum(ems_c_num_occupy[v])) for v in range(len(ems_c_occupy_s))]
        #         for v in range(len(ems_c_occupy)):
        #             model.Add(ems_c_occupy_s[v] > 0).OnlyEnforceIf(ems_c_occupy[v])
        #             model.Add(ems_c_occupy_s[v] <= 0).OnlyEnforceIf(ems_c_occupy[v].Not())
        #         if total_ems_cargo_num[i] < portEmsLpnNum2:
        #             model.Add(sum(ems_c_occupy) <= 1)
        #         elif total_ems_cargo_num[i] >= portEmsLpnNum2 and total_ems_cargo_num[i] <= portEmsLpnNum3:
        #             model.Add(sum(ems_c_occupy) <= 2)
        #         elif total_ems_cargo_num[i] > portEmsLpnNum3:
        #             model.Add(sum(ems_c_occupy) <= 3)
        # else:
        #     if total_zz_cargo_num[i] >0:
        #         [model.Add(zz_c_occupy_s[v] == sum(zz_c_num_occupy[v])) for v in range(len(zz_c_occupy_s))]
        #         for v in range(len(zz_c_occupy)):
        #             model.Add(zz_c_occupy_s[v] > 0).OnlyEnforceIf(zz_c_occupy[v])
        #             model.Add(zz_c_occupy_s[v] <= 0).OnlyEnforceIf(zz_c_occupy[v].Not())
        #         if total_zz_cargo_num[i] < portSelfLpnNum2:
        #             model.Add(sum(zz_c_occupy) <= 1)
        #         elif total_zz_cargo_num[i] >= portSelfLpnNum2:
        #             model.Add(sum(zz_c_occupy) <= 2)

        if total_cargo_num[i] >0:
            [model.Add(c_occupy_s[zz_floor[i]][v] == sum(c_num_occupy[zz_floor[i]][v])) for v in range(len(c_occupy_s[zz_floor[i]]))]
            for v in range(len(c_occupy[zz_floor[i]])):
                model.Add(c_occupy_s[zz_floor[i]][v] > 0).OnlyEnforceIf(c_occupy[zz_floor[i]][v])
                model.Add(c_occupy_s[zz_floor[i]][v] <= 0).OnlyEnforceIf(c_occupy[zz_floor[i]][v].Not())

            for port_assignment_idx in range(len(port_assignment_map[zz_floor[i]])-1):
                if total_cargo_num[i] >= port_assignment_map[zz_floor[i]][port_assignment_idx][1] and total_cargo_num[i]<= port_assignment_map[zz_floor[i]][port_assignment_idx+1][1]:
                    model.Add(sum(c_occupy[zz_floor[i]]) == port_assignment_map[zz_floor[i]][port_assignment_idx][0])

        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)  # 所有订单完成了，厂家完成了
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())

        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_ssub_job)
        job_p_list.append(job_p_sub)

    #
    # if (is_splitting_car==False):
    #     for i in range(1,len(order_sequence)):
    #         for j in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]])):
    #             for k in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j])):
    #                 for a in range(len(job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]])):
    #                     for u in range(len(job_p_list[order_sequence[i - 1][0]][order_sequence[i - 1][1]][a])):
    #                         model.Add(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j][k][0]>=job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]][a][u][1])

    port_num_sum = {}
    sub_port_num_sum = 0
    for floor_port_num in (floor_port_num_map):
        port_num_sum[floor_port_num] = sub_port_num_sum
        sub_port_num_sum += floor_port_num_map[floor_port_num]

    # 接下来分配通达，并计算运输时间
    for i in range(len(job_data)):  # 厂家层级遍历
        for j in range(len(job_data[i])):  # 订单层级遍历
            x_tt_intervals = []
            for e in range(len(job_data[i][j])):  # 车辆遍历
                ini = []
                cd = []
                mm_v = model.NewIntVar(0, max_time, 'p_e_%d_%d' % (i, j))
                for p in range(len(job_data[i][j][e])):  # 货物类型遍历
                    total_interval = 0  # 速度总和的变量
                    if job_type[i][j][e][p] == 1:  # 和EMS共享通道
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer[zz_floor[i]]
                    else:
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer['plt']
                    t_i = model.NewIntVar(1, 99999999, 't_i_%d' % j)
                    model.Add(t_i == total_interval + 1)  # 速度计算待处理
                    I = model.NewIntVar(0, 99999999, 'In_%d' % j)
                    model.AddDivisionEquality(I, job_data[i][j][e][p] * 10000, t_i)
                    ini.append(job_p_list[i][j][e][p][0])
                    cd.append(I)

                    kk = 0
                    if job_type[i][j][e][p] == 1:  # 件箱货物形态
                        # if c[i][j][0][0] == 1:  # 去负一楼
                        #     for u in range(len(c[i][j][0])):
                        #         if c[i][j][0][u] == 1:  # 通道可用，构建矩形
                        #             y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, u))
                        #             j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                        #                                                              job_p_list[i][j][e][p][1],
                        #                                                              total_C_list[i][j][e][p][u // 2],
                        #                                                              'p_%d_%d_%d_%d' % (
                        #                                                              i, j, p, u // 2))
                        #
                        #             j_sub_c_intervals = model.NewOptionalIntervalVar(a_c + u, 1, y_end,
                        #                                                              total_C_list[i][j][e][p][u // 2],
                        #                                                              'c_%d_%d_%d_%d' % (
                        #                                                              i, j, p, u // 2))
                        #
                        #             kk += 1
                        #             rs_c.append(j_sub_p_intervals) #最大容量约束
                        #             rs_zz_delivery_count.append(j_sub_p_intervals) #最大自制通道约束
                        #             de.append(int(V_j[2]))
                        #             x_intervals.append(j_sub_p_intervals)
                        #             y_intervals.append(j_sub_c_intervals)
                        # else:  # 和EMS共享
                        #     # ccc = [1, 1, 1, 1, 1, 1, 1]  # 需修改，待处理
                        #     ccc = ems_c[0][0][0]
                        #     for u in range(len(ccc)):
                        #         if ccc[u] == 1:  # 通道可用，构建矩形
                        #             y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, u))
                        #             j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                        #                                                              job_p_list[i][j][e][p][1],
                        #                                                              total_C_list[i][j][e][p][u],
                        #                                                              'p_%d_%d_%d_%d' % (i, j, p, u))
                        #
                        #             j_sub_c_intervals = model.NewOptionalIntervalVar(a_c + u + 1, 1, y_end,
                        #                                                              total_C_list[i][j][e][p][u],
                        #                                                              'c_%d_%d_%d_%d' % (i, j, p, u))
                        #             kk += 1
                        #             rs_c.append(j_sub_p_intervals) #最大容量约束
                        #             rs_ems_delivery_count.append(j_sub_p_intervals) #最大ems通道约束
                        #             de.append(int(V_j[1]))
                        #             x_intervals.append(j_sub_p_intervals)
                        #             y_intervals.append(j_sub_c_intervals)
                        #
                        for u in range(floor_port_num_map[zz_floor[i]]):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, u))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][u],
                                                                             'p_%d_%d_%d_%d' % (
                                                                                 i, j, p, u))
                            j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum[zz_floor[i]] + u, 1, y_end,
                                                                             total_C_list[i][j][e][p][u],
                                                                             'c_%d_%d_%d_%d' % (
                                                                                 i, j, p, u))

                            kk += 1
                            rs_c.append(j_sub_p_intervals)  # 最大容量约束
                            rs_zz_delivery_count.append(j_sub_p_intervals)  # 最大自制通道约束
                            de.append(int(floor_speed_map_integer[zz_floor[i]]))
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)




                    else:  # 栈板货物形态

                        # for u in range(len(c[i][j][1])):
                        #     if c[i][j][1][u] == 1:  # 口可用，构建矩形
                        #         y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                        #         j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                        #                                                          job_p_list[i][j][e][p][1],
                        #                                                          total_C_list[i][j][e][p][kk],
                        #                                                          'p_%d_%d_%d_%d' % (i, j, p, kk))
                        #
                        #         j_sub_c_intervals = model.NewOptionalIntervalVar(u, 1, y_end,
                        #                                                          total_C_list[i][j][e][p][kk],
                        #                                                          'c_%d_%d_%d_%d' % (i, j, p, kk))
                        #         kk += 1
                        #         x_intervals.append(j_sub_p_intervals)
                        #         y_intervals.append(j_sub_c_intervals)

                        for u in range(floor_port_num_map['plt']):

                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'p_%d_%d_%d_%d' % (i, j, p, kk))

                            j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum['plt'], 1, y_end,
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'c_%d_%d_%d_%d' % (i, j, p, kk))
                            kk += 1
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)

                if len(ini) == 2:  # 若一辆车有两种类型的货物
                    model.Add(ini[0] == ini[1])  # 限制开始处理时间相同
                    model.Add(bool_sub_job_list[i][j][e][0] == bool_sub_job_list[i][j][e][1])
                    I_v = model.NewIntVar(0, 99999999, 'p_e_%d_%d' % (i, j))
                    model.AddMaxEquality(I_v, cd)
                    j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], I_v + int(zz_interval_time[i]) + 1, mm_v,
                                                                       bool_sub_job_list[i][j][e][0],
                                                                       '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    x_tt_intervals.append(j_sub_p_I_intervals)
                else:
                    j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], cd[0] + int(zz_interval_time[i]) + 1,
                                                                       mm_v,
                                                                       bool_sub_job_list[i][j][e][0],
                                                                       '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    x_tt_intervals.append(j_sub_p_I_intervals)

            model.AddNoOverlap(x_tt_intervals)

    load_rate = []

    for i in range(len(job_data)): #计算装载率
        sub_load_rate = []
        for j in range(len(job_data[i])):
            for k in range(len(job_data[i][j])):
                total_goods = 0
                for p in range(len(job_data[i][j][k])):
                    if job_type[i][j][k][p] == 0:
                        total_goods += job_data[i][j][k][p] * zhuan_hua_zz[i]
                    else:
                        total_goods += job_data[i][j][k][p]
                sub_load_rate.append(total_goods / rong_liang_zz[i])
        load_rate.append(sub_load_rate)

    load_rate_index = []

    for i in range(len(load_rate)):
        sub_load_rate = sorted(enumerate(load_rate[i]), key=lambda x: x[1], reverse=True)
        sub_load_index = [ind for ind, _ in sub_load_rate]
        load_rate_index.append(sub_load_index)

    for i in range(len(load_rate_index)):    # 装载率高的优先排前面
        if len(load_rate_index[i]) > 1:
            for k in range(len(load_rate_index[i]) - 1):
                model.Add(
                    job_p_list[i][0][load_rate_index[i][k]][0][0] < job_p_list[i][0][load_rate_index[i][k + 1]][0][0])

    # for i in range(len(job_p_list)):
    #     for j in range(len(job_p_list[i])):
    #         if len(job_p_list[i][j]) > 1:
    #             for k in range(len(job_p_list[i][j]) - 1):
    #                 model.Add(job_p_list[i][j][k][0][0] < job_p_list[i][j][k + 1][0][0])

    de_zz_delivery_count = [1] * len(rs_zz_delivery_count)
    de_ems_delivery_count = [1] * len(rs_ems_delivery_count)
    model.AddNoOverlap2D(x_intervals, y_intervals)
    model.AddCumulative(rs_c, de, int(10000 * dis * box_flow_value))  #最大容量约束
    model.AddCumulative(rs_zz_delivery_count, de_zz_delivery_count, zz_delivery_count)  #最大自制通道约自制
    model.AddCumulative(rs_ems_delivery_count, de_ems_delivery_count, ems_delivery_count)  #最大ems通道约束


    # priority_index = sorted(zz_priority)
    # car_first_start_time = []
    # for i in range(len(job_p_list)):
    #     sub_car_first_start_time = []
    #     for j in range(len(job_p_list[i])):
    #         for k in range(len(job_p_list[i][j])):
    #             sub_car_first_start_time.append(job_p_list[i][j][k][0][0])
    #     car_first_start_time.append(sub_car_first_start_time)

    # for i in range(len(car_first_start_time) - 1):
    #     first_start_time = model.NewIntVar(0, 99999, 'first_start_time_%d' % i)
    #     next_first_start_time = model.NewIntVar(0, 99999, 'first_start_time_%d' % (i + 1))
    #     model.AddMinEquality(first_start_time, car_first_start_time[i])
    #     model.AddMinEquality(next_first_start_time, car_first_start_time[i + 1])
    #     model.Add(first_start_time <= next_first_start_time)

    priority_index = sorted(zz_priority)
    car_first_start_time = []
    for i in range(len(job_p_list)):
        sub_car_first_start_time = []
        for j in range(len(job_p_list[i])):
            for k in range(len(job_p_list[i][j])):
                sub_car_first_start_time.append(job_p_list[i][j][k][0][0])
        car_first_start_time.append(sub_car_first_start_time)

    left = 0
    for i in range(1, len(car_first_start_time)):
        if (priority_index[i] > priority_index[i - 1]):
            for j in range(left, i):
                first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % i)
                next_first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % (i + 1))
                model.AddMinEquality(first_start_time, car_first_start_time[j])
                model.AddMinEquality(next_first_start_time, car_first_start_time[i])
                model.Add(first_start_time <= next_first_start_time)
            left = i


    model.Maximize(total_bbb)  # 最大化排进去的车
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = t
    solver.parameters.random_seed = 0
    status1 = solver.Solve(model)

    # 得到最终的解
    solution_find = False

    if status1 == cp_model.OPTIMAL or status1 == cp_model.FEASIBLE:
        model.Add(total_bbb == round(solver.ObjectiveValue()))
        model.Minimize(sum(min_end_time))
        status2 = solver.Solve(model)
        if status2 == cp_model.OPTIMAL or status2 == cp_model.FEASIBLE:
            solution_find = True
            if status1 == cp_model.OPTIMAL and status2 == cp_model.OPTIMAL:
                logger.info("自制时间窗模型求得最优解")
            elif (status1 == cp_model.FEASIBLE or status1 == cp_model.OPTIMAL) and (status2 == cp_model.FEASIBLE or status2 == cp_model.OPTIMAL):
                logger.info("自制时间窗模型求得次优解")
            else:
                logger.info("自制时间窗模型无解,程序结束")
                # exit()
    if solution_find == False:
        logger.error("自制时间窗模型无解,程序结束")
        # exit()

    # model.Maximize(total_bbb)  # 最大化排进去的车
    # solver = cp_model.CpSolver()
    # solver.parameters.num_search_workers = 8
    # solver.parameters.max_time_in_seconds = t
    # status = solver.Solve(model)
    #
    # # 得到最终的解
    # solution_find = False
    # if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
    #     solution_find = True
    #     if status == cp_model.OPTIMAL:
    #         logger.info("自制时间窗模型求得最优解")
    #     if status == cp_model.FEASIBLE:
    #         logger.info("自制时间窗模型求得次优解")
    # if solution_find == False:
    #     logger.error("自制时间窗模型无解")


    for i in range(len(job_data)):  # 厂家层级遍历
        solu_x_sub = []
        for j in range(len(job_data[i])):  # 订单层级遍历
            u_solu_x_sub = []
            for g in range(len(job_data[i][j])):  # 车辆层级遍历
                so = []
                for k in range(len(job_data[i][j][g])):  # 货物层级遍历
                    solution_x = []
                    if not solution_find: #无解则用0填充解
                        solution_x.append(0)
                        solution_x.append(0)
                    else:
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][0]))
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][1]))
                    so.append(solution_x)
                u_solu_x_sub.append(so)
            solu_x_sub.append(u_solu_x_sub)
        solution_x_total.append(solu_x_sub)

    for i in range(len(job_data)):  # 厂家层级遍历
        solu_bool_sub = []
        for j in range(len(job_data[i])):   # 订单层级遍历
            u_solu_bool_sub = []
            for g in range(len(job_data[i][j])):  # 车辆层级遍历
                so = []
                for k in range(len(job_data[i][j][g])):  # 货物层级遍历
                    if not solution_find: #无解则用0填充最后解
                        so.append(0)
                    else:
                        so.append(solver.Value(bool_sub_job_list[i][j][g][k]))
                u_solu_bool_sub.append(so)
            solu_bool_sub.append(u_solu_bool_sub)
        solution_bool_sub_job.append(solu_bool_sub)

    for i in range(len(job_data)): # 厂家层级遍历
        solu_C_sub = []
        for j in range(len(job_data[i])): # 订单层级遍历
            solu_C_sub_sub = []
            for e in range(len(job_data[i][j])): # 车辆层级遍历
                u_solu_C_sub_sub = []
                if len(job_data[i][j][e]) == 2:
                    so = []
                    c_index_list = []
                    for p in range(len(job_data[i][j][e])): # 货物层级遍历
                        # so = []
                        if job_type[i][j][e][p] == 1:
                            c_index_list.append(p)

                        # if job_type[i][j][e][p] == 0:
                        #     c_index_list.append(p)

                    for p in range(len(job_data[i][j][e])):
                        # so = []
                        # if job_type[i][j][e][p] == 1:
                        #     c_index_list.append(p)

                        if job_type[i][j][e][p] == 0:
                            c_index_list.append(p)

                    for w in range(len(total_C_list[i][j][e][c_index_list[0]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[0]][w]))

                    # if (c[i][0][0][0] == 0):
                    #     so = copy.deepcopy([so[random_ems_index[i]] for i in range(len(random_ems_index))])
                    # else:
                    #     so = copy.deepcopy([so[random_zz_index[i]] for i in range(len(random_zz_index))])
                    # so = copy.deepcopy([so[random_index[zz_floor[i]][k]] for k in range(len(random_index[zz_floor[i]]))])
                    for w in range(len(total_C_list[i][j][e][c_index_list[1]])):
                        if not solution_find:#无解则用0填充最后解
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[1]][w]))



                    u_solu_C_sub_sub.append(so)

                else:
                    so = []
                    if job_type[i][j][e][0] == 1:  # 如果是件箱
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:#无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))
                        # if (c[i][0][0][0] == 0):
                        #     so = copy.deepcopy([so[random_ems_index[i]] for i in range(len(random_ems_index))])
                        # else:
                        #     so = copy.deepcopy([so[random_zz_index[i]] for i in range(len(random_zz_index))])
                        # so = copy.deepcopy([so[random_index[zz_floor[i]][k]] for k in range(len(random_index[zz_floor[i]]))])

                        so = so + [0] * floor_port_num_map['plt']
                        u_solu_C_sub_sub.append(so)
                    else:  # 如果是栈板
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:#无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))
                        # if (c[i][0][0][0] == 1):
                        #     so = [0] * (len(c[i][0][0]) // 2) + so
                        # else:
                        #     so = [0] * len(ems_c[0][0][0]) + so
                        so = [0] * floor_port_num_map[zz_floor[i]] + so
                        u_solu_C_sub_sub.append(so)
                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C.append(solu_C_sub)

    for i in range(len(job_data)): # 厂家层级遍历
        solu_C_sub = []
        for j in range(len(job_data[i])): # 订单层级遍历
            solu_C_sub_sub = []
            for e in range(len(job_data[i][j])): # 车辆层级遍历
                u_solu_C_sub_sub = []
                for p in range(len(job_data[i][j][e])): # 货物层级遍历
                    so = []
                    k = 0
                    if job_type[i][j][e][p] == 1:
                        for w in range(len(total_C_list[i][j][e][p])):
                            if not solution_find:#无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][p][w]))

                    else:
                        for z in range(floor_port_num_map['plt']):
                            if not solution_find:#无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][p][k]))
                            k += 1

                    u_solu_C_sub_sub.append(so)
                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C_N.append(solu_C_sub)

    return solution_x_total, solution_bool_sub_job, solution_bool_C, solution_bool_C_N


def solve(job_data, d_list, job_type, data_end_start, sxt, sbsj, sbc, s_job_type, V_j, s_c, c, p_num, a_c, dis, t,
          ems_interval_time, rong_liang_EMS, zhuan_hua_EMS, box_flow_value, zz_delivery_count, ems_delivery_count,
          ems_priority, max_time,work_time_list, interval_time,random_index,random_ems_index,random_zz_index,portEmsLpnNum3,portEmsLpnNum2,portSelfLpnNum2,order_sequence,is_splitting_car,floor_port_num_map,ems_floor,zz_floor,port_assignment_map,floor_speed_map,logger):
    """
    该函数用于求解时间窗，输入输出参数解释如下
    :param job_data:EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
    :param d_list:EMS货物的截止日期
    :param job_type:EMS货物形态 0可代表栈板，1代表件箱，2代表gtp
    :param data_end_start:各个任务对应的开始时间
    :param sxt:所有自制子任务的开始处理时间和处理结束时间，单位为秒，维度1,维度2,维度3,维度4 = 厂家,订单,车辆，时间
    :param sbsj:该项对应某一个自制子任务是否被处理，若为1则被处理，若为0则没被处理；维度1,维度2,维度3,维度4 = 厂家,订单,车辆，是否被处理
    :param sbc:方便EMS求解使用的通道参数；维度1,维度2,维度3,维度4 = 厂家,订单,车辆，通道号
    :param s_job_type: 每辆车装的总货物类型；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物类型
    :param V_j: 不同类型货物对应通道的速度，数量/秒，0的位置对应栈板，1的位置对应件箱，2的位置对应自制
    :param s_c:对应于自制的可用通道；维度1，维度2，维度3 =  厂家，订单，货物类型，通道类型和数量；[0,1]表示1楼，[1,0]表示-1楼； 第三个维度前件箱，后栈板；如 s_c = [[[[1, 0, 1, 0], [1, 1, 1]]], [[[0, 1], [1, 1, 1]]]]表示第一个厂家安排了负1楼件箱通道2个,栈板通道3个;第二个厂家安排了1楼件箱通道1个,栈板通道3个
    :param c: 可用的通道
    :param p_num: 所有件箱的通道
    :param a_c: 所有栈板的通道
    :param t:求解时间，若最后无解，则需调大时间
    :param dis:打折系数
    :param ems_interval_time:ems间隔时间
    :param rong_liang_EMS:ems最大容量
    :param zhuan_hua_EMS:ems转化系数
    :param box_flow_value:最大流量
    :param zz_delivery_count:最大自制通道限制
    :param ems_delivery_count:最大ems通道限制
    :param max_time:归一化后所有时间戳相关参数的最大时间
    :param interval_time:ems发车间隔时间
    :param ems_priority: ems优先级
    :return: solution_x_total 所有子任务的开始处理时间和处理结束时间，单位为秒
    solution_bool_sub_job 该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理
    solution_bool_C 该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用
    """
    # # 对速度进行折扣处理
    # for v in range(len(V_j)):
    #     if int(V_j[v] * dis) != 0:
    #         V_j[v] = int(V_j[v] * dis)
    #     else:
    #         V_j[v] = 1
    if (is_splitting_car==False):
        max_time = 999999999
    total_ems_cargo_num = get_ems_cargo_num(job_data, job_type)
    total_cargo_num = get_cargo_num_(job_data, job_type)

    # 对速度进行折扣处理
    for v in range(len(V_j)):
        V_j[v] = int(V_j[v] * dis * 10000)

    floor_speed_map_integer = {}
    for v in floor_speed_map:
        floor_speed_map_integer[v] = int(floor_speed_map[v] * dis * 10000)#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    total_C_list = []
    bool_job_list = []
    bool_sub_job_list = []
    job_p_list = []
    x_intervals = []
    y_intervals = []
    solution_x_total = []
    solution_bool_sub_job = []
    solution_bool_C = []
    rs_zz_delivery_count = []
    rs_ems_delivery_count = []
    de = []
    rs_c = []
    min_end_time = []
    total_bb = 0
    total_bbb = 0

    model = cp_model.CpModel()



    for i in range(len(job_data)):  # 厂家层级遍历
        ts = data_end_start[i]
        j_b = model.NewBoolVar('%d' % i)  # 该厂家的车是否全部排完
        total_bb += j_b
        bool_job_list.append(j_b)
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        bool_sub_ssub_job = []

        c_num_occupy = {}
        for port_num in floor_port_num_map:
            c_num_occupy[port_num] = [[] for _ in range(floor_port_num_map[port_num])]
        c_occupy_s = {}
        for j,port_num in enumerate(floor_port_num_map):
            c_occupy_s[port_num] = [model.NewIntVar(0, 100, 'p_e_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]
        c_occupy = {}
        for j,port_num in enumerate(floor_port_num_map) :
            c_occupy[port_num] = [model.NewBoolVar('ocp_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]

        # ems_c_num_occupy = [[] for _ in range(len(random_ems_index))]
        # zz_c_num_occupy = [[] for _ in range(len(random_zz_index))]
        # ems_c_occupy_s = [model.NewIntVar(0, 100, 'p_e_%d' % (i)) for i in range(len(random_ems_index))]
        # zz_c_occupy_s = [model.NewIntVar(0, 100, 'p_e_%d' % (i)) for i in range(len(random_zz_index))]
        # ems_c_occupy = [model.NewBoolVar('ocp_%d' % (i)) for i in range(len(random_ems_index))]
        # zz_c_occupy = [model.NewBoolVar('ocp_%d' % (i)) for i in range(len(random_zz_index))]
        # ems_c_num_occupy = [[] for _ in range(len(random_ems_index))]
        # ems_c_occupy_s = [model.NewIntVar(0, 100, 'p_e_%d' % (i)) for i in range(len(random_ems_index))]
        # ems_c_occupy = [model.NewBoolVar('ocp_%d' % (i)) for i in range(len(random_ems_index))]
        for j in range(len(job_data[i])):  # 订单层级的遍历
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))  # 订单是否完成
            bool_sub_job.append(j_sub_b)
            u_bool_sub_sub_job = []
            u_job_p_sub_sub = []
            u_sub_C_list = []
            u_bool_sub_job_se = []


            for k in range(len(job_data[i][j])):  # 车辆层级遍历
                u_j_sub_b_se = model.NewBoolVar('%d_%d_%d' % (i, j, k))
                u_bool_sub_job_se.append(u_j_sub_b_se)

                bool_sub_sub_job = []
                job_p_sub_sub = []
                sub_C_list = []
                for p in range(len(job_data[i][j][k])):  # 车内部货物类型层级遍历（件箱、栈板）
                    j_sub_sub_b = model.NewBoolVar('%d_%d_%d_%d' % (i, j, k, p))  # 货物是否被分配通道并在交期内处理
                    bool_sub_sub_job.append(j_sub_sub_b)
                    total_bbb += j_sub_sub_b
                    sub_sub_c_list = []
                    sub_sub_p_list = []
                    j_sub_p_s = model.NewIntVar(ts, max_time, 'p_s_%d_%d_%d_%d' % (i, j, k, p))  # 货物开始处理时间变量
                    j_sub_p_e = model.NewIntVar(ts, max_time, 'p_e_%d_%d_%d_%d' % (i, j, k, p))  # 货物结束处理时间变量
                    j_sub_p_e_1 = model.NewIntVar(ts, max_time, 'p_e1_%d_%d_%d_%d' % (i, j, k, p))  # 用于车辆时间间隔的变量
                    min_end_time.append(j_sub_p_e)
                    due_data_d = model.NewBoolVar('due_data_d')  # 交期是否满足的变量
                    c_d = model.NewBoolVar('c_d')  # 是否分配通道的变量
                    model.Add(j_sub_p_e <= d_list[i]).OnlyEnforceIf(due_data_d)  # 交期约束
                    model.Add(j_sub_p_e > d_list[i]).OnlyEnforceIf(due_data_d.Not())  # 交期约束
                    sub_sub_p_list.append(j_sub_p_s)
                    sub_sub_p_list.append(j_sub_p_e)
                    sub_sub_p_list.append(j_sub_p_e_1)
                    job_p_sub_sub.append(sub_sub_p_list)
                    # if job_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                    #     for v in range(len(c[i][j][1])):  # 遍历通道
                    #         if c[i][j][1][v] == 1:  # 通道可以使用，为0则是被禁用
                    #             b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, 7))
                    #             sub_sub_c_list.append(b)
                    # else:
                    #     for m in range(len(c[i][j][0])):
                    #         if c[i][j][0][m] == 1:
                    #             b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                    #             sub_sub_c_list.append(b)
                    #             ems_c_num_occupy[m].append(b)

                    if job_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                        for v in range(floor_port_num_map['plt']):  # 遍历通道
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, 7))
                            sub_sub_c_list.append(b)
                    else:
                        for m in range(floor_port_num_map[ems_floor[i]]):
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                            sub_sub_c_list.append(b)
                            c_num_occupy[ems_floor[i]][m].append(b)


                    model.Add(sum(sub_sub_c_list) <= job_data[i][j][k][p])
                    model.Add(sum(sub_sub_c_list) > 0).OnlyEnforceIf(c_d)  # 分配通道，c_d为1
                    model.Add(sum(sub_sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
                    # model.Add(due_data_d == 1).OnlyEnforceIf(c_d)
                    model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_sub_b)  # 交期通道两个全满足，货物进去
                    model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_sub_b.Not())
                    sub_C_list.append(sub_sub_c_list)
                u_job_p_sub_sub.append(job_p_sub_sub)
                u_sub_C_list.append(sub_C_list)
                u_bool_sub_sub_job.append(bool_sub_sub_job)
                model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(
                    u_j_sub_b_se)  # 件箱和栈板全部排入或件箱、栈板排入就代表车排入了
                model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(u_j_sub_b_se.Not())


            model.Add(sum(u_bool_sub_job_se) == len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b)  # 车全排入了，就代表订单完成了
            model.Add(sum(u_bool_sub_job_se) < len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b.Not())

            C_list.append(u_sub_C_list)
            bool_sub_ssub_job.append(u_bool_sub_sub_job)
            job_p_sub.append(u_job_p_sub_sub)
            # model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(j_sub_b)
            # model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(j_sub_b.Not())

        # if total_ems_cargo_num[i] > 0:
        #     [model.Add(ems_c_occupy_s[v] == sum(ems_c_num_occupy[v])) for v in range(len(ems_c_occupy_s))]
        #     for v in range(len(ems_c_occupy)):
        #         model.Add(ems_c_occupy_s[v] > 0).OnlyEnforceIf(ems_c_occupy[v])
        #         model.Add(ems_c_occupy_s[v] <= 0).OnlyEnforceIf(ems_c_occupy[v].Not())
        #     if total_ems_cargo_num[i] <= portEmsLpnNum2:
        #         model.Add(sum(ems_c_occupy) <= 1)
        #     if total_ems_cargo_num[i] > portEmsLpnNum2 and total_ems_cargo_num[i] <= portEmsLpnNum3:
        #         model.Add(sum(ems_c_occupy) <= 2)
        #     if total_ems_cargo_num[i] >= portEmsLpnNum3:
        #         model.Add(sum(ems_c_occupy) <= 3)

        if total_cargo_num[i] >0:
            [model.Add(c_occupy_s[ems_floor[i]][v] == sum(c_num_occupy[ems_floor[i]][v])) for v in range(len(c_occupy_s[ems_floor[i]]))]
            for v in range(len(c_occupy[ems_floor[i]])):
                model.Add(c_occupy_s[ems_floor[i]][v] > 0).OnlyEnforceIf(c_occupy[ems_floor[i]][v])
                model.Add(c_occupy_s[ems_floor[i]][v] <= 0).OnlyEnforceIf(c_occupy[ems_floor[i]][v].Not())

            for port_assignment_idx in range(len(port_assignment_map[ems_floor[i]])-1):
                if total_cargo_num[i] >= port_assignment_map[ems_floor[i]][port_assignment_idx][1] and total_cargo_num[i]<= port_assignment_map[ems_floor[i]][port_assignment_idx+1][1]:
                    model.Add(sum(c_occupy[ems_floor[i]]) <= port_assignment_map[ems_floor[i]][port_assignment_idx][0])

        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)  # 所有订单完成了，厂家完成了
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())

        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_ssub_job)
        job_p_list.append(job_p_sub)


    # if (is_splitting_car==False):
    #     for i in range(1,len(order_sequence)):
    #         for j in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]])):
    #             for k in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j])):
    #                 for a in range(len(job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]])):
    #                     for u in range(len(job_p_list[order_sequence[i - 1][0]][order_sequence[i - 1][1]][a])):
    #                             model.Add(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j][k][0]>=job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]][a][u][1])

    # 之前自制的求解，在此处作为常数矩形

    port_num_sum = {}
    sub_port_num_sum = 0
    for floor_port_num in (floor_port_num_map):
        port_num_sum[floor_port_num] = sub_port_num_sum
        sub_port_num_sum += floor_port_num_map[floor_port_num]

    for g in range(len(sxt)):
        for i in range(len(sxt[g])):
            for k in range(len(sxt[g][i])):
                for p in range(len(sxt[g][i][k])):
                    if s_job_type[g][i][k][p] == 1:  # 如果是件箱
                        for l in range(len(sbc[g][i][k][p])):
                            if sbc[g][i][k][p][l]:  # 如果通道启用
                                x_s = model.NewConstant(sxt[g][i][k][p][0])
                                ii = model.NewConstant(sxt[g][i][k][p][1] - sxt[g][i][k][p][0])
                                x_e = model.NewConstant(sxt[g][i][k][p][1])
                                y_s = model.NewConstant(l + port_num_sum[zz_floor[g]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(l + 1 + port_num_sum[zz_floor[g]])

                                if sbsj[g][i][k][p] == 1:
                                    x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, sbsj[g][i][k][p],
                                                                        'x_ii%d' % i)
                                    y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, sbsj[g][i][k][p],
                                                                        'y_ii%d' % i)
                                    x_intervals.append(x_ii)
                                    y_intervals.append(y_ii)
                                    de.append(floor_speed_map_integer[zz_floor[g]])
                                    rs_c.append(x_ii)
                                    rs_ems_delivery_count.append(x_ii)
                    else:
                        for l in range(len(sbc[g][i][k][p])):
                            if sbc[g][i][k][p][l]:
                                x_s = model.NewConstant(sxt[g][i][k][p][0])
                                ii = model.NewConstant(sxt[g][i][k][p][1] - sxt[g][i][k][p][0])
                                x_e = model.NewConstant(sxt[g][i][k][p][1])
                                y_s = model.NewConstant(l+ port_num_sum['plt'])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(l + 1 + port_num_sum['plt'])
                                if sbsj[g][i][k][p] == 1:
                                    x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, sbsj[g][i][k][p], 'x_ii%d' % i)
                                    y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, sbsj[g][i][k][p], 'y_ii%d' % i)
                                    x_intervals.append(x_ii)
                                    y_intervals.append(y_ii)

    # 之前自制的求解，在此处作为常数矩形
    # for g in range(len(sxt)):
    #     for i in range(len(sxt[g])):
    #         for k in range(len(sxt[g][i])):
    #             for p in range(len(sxt[g][i][k])):
    #                 if s_job_type[g][i][k][p] == 1:  # 如果是件箱
    #                     if s_c[g][0][0][0] == 1:  # 负一楼
    #                         for l in range(len(sbc[g][i][k][p])):
    #                             if sbc[g][i][k][p][l]:  # 如果通道启用
    #                                 x_s = model.NewConstant(sxt[g][i][k][p][0])
    #                                 ii = model.NewConstant(sxt[g][i][k][p][1] - sxt[g][i][k][p][0])
    #                                 x_e = model.NewConstant(sxt[g][i][k][p][1])
    #                                 y_s = model.NewConstant(l + p_num + a_c)
    #                                 iii = model.NewConstant(1)
    #                                 y_e = model.NewConstant(l + p_num + a_c + 1)
    #                                 if sbsj[g][i][k][p] == 1:
    #                                     x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, sbsj[g][i][k][p],
    #                                                                         'x_ii%d' % i)
    #                                     y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, sbsj[g][i][k][p],
    #                                                                         'y_ii%d' % i)
    #                                     x_intervals.append(x_ii)
    #                                     y_intervals.append(y_ii)
    #                                     de.append(V_j[2])
    #                                     rs_c.append(x_ii)
    #                                     rs_zz_delivery_count.append(x_ii)
    #                     else:  # 一楼，与ems共享
    #                         for l in range(len(sbc[g][i][k][p])):
    #                             if sbc[g][i][k][p][l]:
    #                                 x_s = model.NewConstant(sxt[g][i][k][p][0])
    #                                 ii = model.NewConstant(sxt[g][i][k][p][1] - sxt[g][i][k][p][0])
    #                                 x_e = model.NewConstant(sxt[g][i][k][p][1])
    #                                 y_s = model.NewConstant(l)
    #                                 iii = model.NewConstant(1)
    #                                 y_e = model.NewConstant(l + 1)
    #                                 if sbsj[g][i][k][p] == 1:
    #                                     x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, sbsj[g][i][k][p],
    #                                                                         'x_ii%d' % i)
    #                                     y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, sbsj[g][i][k][p],
    #                                                                         'y_ii%d' % i)
    #                                     x_intervals.append(x_ii)
    #                                     y_intervals.append(y_ii)
    #                                     de.append(V_j[1])
    #                                     rs_c.append(x_ii)
    #                                     rs_ems_delivery_count.append(x_ii)
    #                 else:
    #                     for l in range(len(sbc[g][i][k][p])):
    #                         if sbc[g][i][k][p][l]:
    #                             x_s = model.NewConstant(sxt[g][i][k][p][0])
    #                             ii = model.NewConstant(sxt[g][i][k][p][1] - sxt[g][i][k][p][0])
    #                             x_e = model.NewConstant(sxt[g][i][k][p][1])
    #                             y_s = model.NewConstant(l + p_num)
    #                             iii = model.NewConstant(1)
    #                             y_e = model.NewConstant(l + p_num + 1)
    #                             if sbsj[g][i][k][p] == 1:
    #                                 x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, sbsj[g][i][k][p], 'x_ii%d' % i)
    #                                 y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, sbsj[g][i][k][p], 'y_ii%d' % i)
    #                                 x_intervals.append(x_ii)
    #                                 y_intervals.append(y_ii)

    # 接下来分配通达，并计算运输时间
    x_tt_ems_itv = []
    x_tt_itv2 = []
    x_tt_itv3 = []
    x_tt_ini = []
    x_tt_mmv = []
    x_tt_is_bool_var = []
    x_tt_cd = []
    for i in range(len(job_data)):  # 厂家层级遍历
        for j in range(len(job_data[i])):  # 订单层级遍历
            x_tt_intervals = []
            for e in range(len(job_data[i][j])):  # 车辆遍历
                ini = []
                cd = []
                mm_v = model.NewIntVar(0, 999999999, 'p_e_%d_%d_%d' % (i, j,e))
                itv2 = model.NewIntVar(-999999999, 999999999, 'itv2_%d_%d_%d' % (i, j, e))
                itv3 = model.NewIntVar(0, 999999999, 'itv3_%d_%d_%d' % (i, j, e))
                itv4 = model.NewIntVar(0, 999999999, 'itv4_%d_%d_%d' % (i, j, e))
                ems_itv = model.NewIntVar(0, 999999999, 'ems_itv_%d_%d_%d' % (i, j, e))
                for p in range(len(job_data[i][j][e])):  # 货物类型遍历
                    total_interval = 0  # 速度总和的变量
                    if job_type[i][j][e][p] == 1:  # 和EMS共享通道
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer[ems_floor[i]]
                    else:
                        for k in range(len(total_C_list[i][j][e][p])):  # 去负一楼
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer['plt']
                    t_i = model.NewIntVar(1, 99999999, 't_i_%d' % j)
                    model.Add(t_i == total_interval + 1)  # 速度计算，待处理
                    I = model.NewIntVar(0, 99999999, 'In_%d' % j)
                    model.AddDivisionEquality(I, job_data[i][j][e][p] * 10000, t_i)
                    ini.append(job_p_list[i][j][e][p][0])
                    cd.append(I)

                    kk = 0
                    if job_type[i][j][e][p] == 1:  # 件箱货物形态

                        for u in range(floor_port_num_map[ems_floor[i]]):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'p_%d_%d_%d_%d' % (i, j, p, kk))
                            j_sub_c_intervals = model.NewOptionalIntervalVar(u+port_num_sum[ems_floor[i]], 1, y_end,
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'c_%d_%d_%d_%d' % (i, j, p, kk))
                            kk += 1
                            rs_c.append(j_sub_p_intervals)
                            rs_ems_delivery_count.append(j_sub_p_intervals)
                            de.append(int(floor_speed_map_integer[ems_floor[i]]))
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)

                    else:
                        for u in range(floor_port_num_map['plt']):
                                y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                                j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                                 job_p_list[i][j][e][p][1],
                                                                                 total_C_list[i][j][e][p][kk],
                                                                                 'p_%d_%d_%d_%d' % (i, j, p, kk))
                                j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum['plt'] + u, 1, y_end,
                                                                                 total_C_list[i][j][e][p][kk],
                                                                                 'c_%d_%d_%d_%d' % (i, j, p, kk))
                                kk += 1
                                x_intervals.append(j_sub_p_intervals)
                                y_intervals.append(j_sub_c_intervals)

                if len(ini) == 2:  # 若一辆车有两种类型的货物
                    model.Add(ini[0] == ini[1])  # 限制开始处理时间相同
                    model.Add(bool_sub_job_list[i][j][e][0] == bool_sub_job_list[i][j][e][1])
                    I_v = model.NewIntVar(0, 99999999, 'p_e_%d_%d' % (i, j))
                    model.AddMaxEquality(I_v, cd)
                    #
                    if len(interval_time) > 0:  #实现真实间隔约束
                        real_time_bool_var = 0
                        for kt in range(len(interval_time)):
                            it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                            rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                            rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                            model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)  #表示开始时间早于不连续区间的标志位
                            model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                            model.Add(mm_v >= work_time_list[kt + 1][0]).OnlyEnforceIf(rag12)#表示结束时间晚于不连续区间的标志位
                            model.Add(mm_v < work_time_list[kt + 1][0]).OnlyEnforceIf(rag12.Not())
                            model.Add(ini[0] + I_v < work_time_list[kt][1]).OnlyEnforceIf(rag13) #表示开始时间加上时间间隔早于不连续区间的标志位
                            model.Add(ini[0] + I_v >= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                            model.AddMultiplicationEquality(it_bool_val, [rag11, rag12]) #表示开始时间早于不连续区间的同时结束时间晚于不连续区间的标志位
                            model.AddMultiplicationEquality(it_bool_val2, [it_bool_val, rag13])#表示开始时间早于不连续区间、结束时间晚于不连续区间、开始时间加上时间间隔早于不连续区间的标志位
                            real_time_bool_var += it_bool_val2 * interval_time[kt]

                        model.Add(itv2 == int(ems_interval_time[i]) - real_time_bool_var)  #若出跨时间间隔，则将这部分时间减去
                        model.AddMaxEquality(itv3, (0, itv2))                    #减完后的时间小于0则为0
                        model.Add(itv4 >= itv3)                                 #真实时间间隔
                        model.Add(itv4 <= int(ems_interval_time[i]))
                        model.Add(ems_itv == I_v + itv4 + 1)
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], ems_itv,
                                                                           mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                           I_v + int(ems_interval_time[i]) + 1,
                                                                           mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    # j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                    #                                                    I_v + int(ems_interval_time[i]) + 1,
                    #                                                    mm_v,
                    #                                                    bool_sub_job_list[i][j][e][0],
                    #                                                    '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    x_tt_intervals.append(j_sub_p_I_intervals)
                else:
                    if len(interval_time) > 0:  #实现真实间隔约束
                        real_time_bool_var = 0
                        for kt in range(len(interval_time)):
                            it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                            rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                            rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                            model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)  #表示开始时间早于不连续区间的标志位
                            model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                            model.Add(mm_v >= work_time_list[kt][1]).OnlyEnforceIf(rag12)#表示结束时间晚于不连续区间的标志位
                            model.Add(mm_v < work_time_list[kt][1]).OnlyEnforceIf(rag12.Not())
                            model.Add(ini[0] +cd[0] < work_time_list[kt][1]).OnlyEnforceIf(rag13) #表示开始时间加上时间间隔早于不连续区间的标志位
                            model.Add(ini[0] +cd[0]>= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                            model.AddMultiplicationEquality(it_bool_val, [rag11, rag12])#表示开始时间早于不连续区间的同时结束时间晚于不连续区间的标志位
                            model.AddMultiplicationEquality(it_bool_val2, [it_bool_val, rag13])#表示开始时间早于不连续区间、结束时间晚于不连续区间、开始时间加上时间间隔早于不连续区间的标志位
                            real_time_bool_var += it_bool_val2 * interval_time[kt]

                        model.Add(itv2 == int(ems_interval_time[i]) - real_time_bool_var)#若出跨时间间隔，则将这部分时间减去
                        model.AddMaxEquality(itv3, (0, itv2))#减完后的时间小于0则为0
                        model.Add(itv4 >= itv3)   #真实时间间隔
                        model.Add(itv4 <= int(ems_interval_time[i]))
                        model.Add(ems_itv == cd[0] + itv4 + 1)
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], ems_itv,
                                                                           mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                           cd[0] + int(ems_interval_time[i]) + 1,
                                                                           mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    # j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                    #                                                    cd[0] + int(ems_interval_time[i]) + 1,
                    #                                                    mm_v,
                    #                                                    bool_sub_job_list[i][j][e][0],
                    #                                                    '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    x_tt_intervals.append(j_sub_p_I_intervals)
                    x_tt_ems_itv.append(ems_itv)
                    x_tt_ini.append(ini[0])
                    x_tt_mmv.append(mm_v)
                    x_tt_itv2.append(itv2)
                    x_tt_itv3.append(itv3)
                    x_tt_cd.append(cd[0])
            model.AddNoOverlap(x_tt_intervals)

    load_rate = []

    for i in range(len(job_data)): #计算装载率
        sub_load_rate = []
        for j in range(len(job_data[i])):
            for k in range(len(job_data[i][j])):
                total_goods = 0
                for p in range(len(job_data[i][j][k])):
                    if job_type[i][j][k][p] == 0:
                        total_goods += job_data[i][j][k][p] * zhuan_hua_EMS[i]
                    else:
                        total_goods += job_data[i][j][k][p]
                sub_load_rate.append(total_goods / rong_liang_EMS[i])
        load_rate.append(sub_load_rate)

    load_rate_index = []

    for i in range(len(load_rate)):
        sub_load_rate = sorted(enumerate(load_rate[i]), key=lambda x: x[1], reverse=True)
        sub_load_index = [ind for ind, _ in sub_load_rate]
        load_rate_index.append(sub_load_index)

    for i in range(len(load_rate_index)):  # 装载率高的优先排前面
        if len(load_rate_index[i]) > 1:
            for k in range(len(load_rate_index[i]) - 1):
                model.Add(
                    job_p_list[i][0][load_rate_index[i][k]][0][0] < job_p_list[i][0][load_rate_index[i][k + 1]][0][0])

    # for i in range(len(job_p_list)):
    #     for j in range(len(job_p_list[i])):
    #         if len(job_p_list[i][j]) > 1:
    #             for k in range(len(job_p_list[i][j]) - 1):
    #                 model.Add(job_p_list[i][j][k][0][0] < job_p_list[i][j][k + 1][0][0])
    de_zz_delivery_count = [1] * len(rs_zz_delivery_count)
    de_ems_delivery_count = [1] * len(rs_ems_delivery_count)

    model.AddNoOverlap2D(x_intervals, y_intervals)
    model.AddCumulative(rs_c, de, int(10000 * dis * box_flow_value))  # 件箱库流量约束
    model.AddCumulative(rs_zz_delivery_count, de_zz_delivery_count, zz_delivery_count) #最大自制通道约自制
    model.AddCumulative(rs_ems_delivery_count, de_ems_delivery_count, ems_delivery_count)   #最大ems通道约束



    # # 优先级逻辑，待处理
    # for i in range(len(job_data) - 1):
    #     model.Add(bool_job_list[i] == 1).OnlyEnforceIf(bool_job_list[i + 1])

    #优先级逻辑
    car_first_start_time = []

    for i in range(len(job_p_list)):
        sub_car_first_start_time = []
        for j in range(len(job_p_list[i])):
            for k in range(len(job_p_list[i][j])):
                sub_car_first_start_time.append(job_p_list[i][j][k][0][0])
        car_first_start_time.append(sub_car_first_start_time)

    for i in range(len(car_first_start_time) - 1):
        first_start_time = model.NewIntVar(0, 99999, 'first_start_time_%d' % i)
        next_first_start_time = model.NewIntVar(0, 99999, 'first_start_time_%d' % (i + 1))
        model.AddMinEquality(first_start_time, car_first_start_time[i])
        model.AddMinEquality(next_first_start_time, car_first_start_time[i + 1])
        model.Add(first_start_time <= next_first_start_time)


    priority_index = sorted(ems_priority)
    car_first_start_time = []
    for i in range(len(job_p_list)):
        sub_car_first_start_time = []
        for j in range(len(job_p_list[i])):
            for k in range(len(job_p_list[i][j])):
                sub_car_first_start_time.append(job_p_list[i][j][k][0][0])
        car_first_start_time.append(sub_car_first_start_time)

    left = 0
    for i in range(1, len(car_first_start_time)):
        if (priority_index[i] > priority_index[i - 1]):
            for j in range(left, i):
                first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % i)
                next_first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % (i + 1))
                model.AddMinEquality(first_start_time, car_first_start_time[j])
                model.AddMinEquality(next_first_start_time, car_first_start_time[i])
                model.Add(first_start_time <= next_first_start_time)
            left = i

    model.Maximize(total_bbb)  # 最大化排进去的车
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = t
    solver.parameters.random_seed = 0
    status1 = solver.Solve(model)

    # 得到最终的解
    solution_find = False

    if status1 == cp_model.OPTIMAL or status1 == cp_model.FEASIBLE:
        model.Add(total_bbb == round(solver.ObjectiveValue()))
        model.Minimize(sum(min_end_time))
        status2 = solver.Solve(model)
        if status2 == cp_model.OPTIMAL or status2 == cp_model.FEASIBLE:
            solution_find = True
            if status1 == cp_model.OPTIMAL and status2 == cp_model.OPTIMAL:
                logger.info("EMS时间窗模型求得最优解")
            elif (status1 == cp_model.FEASIBLE or status1 == cp_model.OPTIMAL) and (status2 == cp_model.FEASIBLE or status2 == cp_model.OPTIMAL):
                logger.info("EMS时间窗模型求得次优解")
            else:
                logger.info("EMS时间窗模型无解,程序结束")
                # exit()
    if solution_find == False:
        logger.error("EMS时间窗模型无解,程序结束")
        # exit()

    for i in range(len(job_data)):
        solu_x_sub = []
        for j in range(len(job_data[i])):
            u_solu_x_sub = []
            for g in range(len(job_data[i][j])):
                so = []
                for k in range(len(job_data[i][j][g])):
                    solution_x = []
                    if not solution_find:
                        solution_x.append(0)
                        solution_x.append(0)
                    else:
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][0]))
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][1]))
                    so.append(solution_x)
                u_solu_x_sub.append(so)
            solu_x_sub.append(u_solu_x_sub)
        solution_x_total.append(solu_x_sub)

    for i in range(len(job_data)):
        solu_bool_sub = []
        for j in range(len(job_data[i])):
            u_solu_bool_sub = []
            for g in range(len(job_data[i][j])):
                so = []
                for k in range(len(job_data[i][j][g])):
                    if not solution_find:
                        so.append(0)
                    else:
                        so.append(solver.Value(bool_sub_job_list[i][j][g][k]))
                u_solu_bool_sub.append(so)
            solu_bool_sub.append(u_solu_bool_sub)
        solution_bool_sub_job.append(solu_bool_sub)

    for i in range(len(job_data)):
        solu_C_sub = []
        for j in range(len(job_data[i])):
            solu_C_sub_sub = []
            for e in range(len(job_data[i][j])):
                u_solu_C_sub_sub = []
                if len(job_data[i][j][e]) == 2:
                    so = []
                    c_index_list = []
                    for p in range(len(job_data[i][j][e])):
                        if job_type[i][j][e][p] == 1:
                            c_index_list.append(p)

                    for p in range(len(job_data[i][j][e])):
                        if job_type[i][j][e][p] == 0:
                            c_index_list.append(p)

                    for w in range(len(total_C_list[i][j][e][c_index_list[0]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[0]][w]))

                    for w in range(len(total_C_list[i][j][e][c_index_list[1]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[1]][w]))

                    u_solu_C_sub_sub.append(so)

                else:
                    so = []
                    if job_type[i][j][e][0] == 1:
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))


                        so = so + [0] * floor_port_num_map['plt']
                        u_solu_C_sub_sub.append(so)
                    else:
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))
                        so = [0] * floor_port_num_map[ems_floor[i]] + so
                        u_solu_C_sub_sub.append(so)

                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C.append(solu_C_sub)

    return solution_x_total, solution_bool_sub_job, solution_bool_C


def solve_all(job_zz_data, job_zz_type, dis, t, zz_interval_time,
    rong_liang_zz, zhuan_hua_zz, box_flow_value, zz_priority, max_time, floor_speed_map, is_splitting_car, floor_port_num_map, ems_floor, zz_floor, port_assignment_map,floor_delivery_num_map,
    job_ems_data, d_ems_list, job_ems_type, ems_data_end_start,
    ems_interval_time, rong_liang_EMS, zhuan_hua_EMS,
    ems_priority, work_time_list, interval_time, zz_n_start_time, zz_n_d_list,zz_car_num,zz_begin_time,zz_end_time, logger):

    '''
    主函数，直接用这个就行
    :param job_zz_data:自制任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列；维度1,维度2,维度3,维度4 = 厂家,订单,车辆，货物数量
    :param job_zz_type:自制货物形态 0可代表栈板，1代表件箱，2代表gtp；维度1,维度2,维度3,维度4 = 厂家,订单,车辆，货物类型
    :param dis:打折系数
    :param t:求解时间
    :param zz_interval_time:自制发车间隔时间
    :param rong_liang_zz:对应于厂家的车辆容量，只有一个维度(自制)
    :param zhuan_hua_zz:对应于厂家的转换系数，只有一个维度(自制)
    :param box_flow_value  流量限制
    :param zz_priority 自制优先级
    :param max_time:最大时间
    :param floor_speed_map  楼层速度参数
    :param is_splitting_car     是否分车
    :param floor_port_num_map   楼层通道参数
    :param ems_floor    ems楼层参数
    :param zz_floor    自制楼层参数
    :param port_assignment_map  每几个货物分配多少通道
    :param floor_delivery_num_map   楼层最大通道数参数
    :param job_ems_data 决策变量，表示某个订单详情放入该厂家的某辆车中的货物数量，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，该厂家的某辆车的货物数量
    :param d_ems_list   ems结束时间
    :param job_ems_type     ems类型
    :param ems_data_end_start   ems开始时间
    :param ems_interval_time:   ems发车间隔时间
    :param rong_liang_EMS:对应于厂家的车辆容量，只有一个维度(EMS)
    :param zhuan_hua_EMS:对应于厂家的转换系数，只有一个维度(EMS)
    :param ems_priority ems优先级
    :param work_time_list   连续化后的时间窗
    :param interval_time    连续化后的时间窗之间的不工作时间段
    :param zz_n_start_time  时间窗连续化后的自制发车表的开始时间
    :param zz_n_d_list  时间窗连续化后的自制发车表的结束时间
    :param zz_car_num   车辆数量
    :param zz_begin_time  对应于自制厂家每辆车的最早开始时间， 维度1，维度2=  厂家，时间
    :param zz_end_time  对应于自制厂家每辆车的最晚结束时间，维度1，维度2=  厂家，时间
    '''
    # 创建cpModel实例
    model = cp_model.CpModel()

    schedule_start = []
    schedule_end = []

    # 自制车次只能选择一个开始时间约束
    # 自制交付对象维度遍历自制车次信息矩阵
    for i in range(len(job_zz_data)):
        sub_schedule_start = []
        sub_schedule_end = []
        # 订单维度遍历
        for j in range(len(job_zz_data[i])):
            sub_sub_schedule_start = []
            sub_sub_schedule_end = []
            # 订单详情层级遍历
            for k in range(len(job_zz_data[i][j])):
                # 为每个订单详情创建一个开始时间和结束时间的整数变量，变量范围从0到99999999
                sub_sub_sub_schedule_start = model.NewIntVar(0, 99999999, 's_s_%d%d%d' % (i, j, k))
                sub_sub_sub_schedule_end = model.NewIntVar(0, 99999999, 's_s_%d%d%d' % (i, j, k))
                sub_sub_sub_schedule_start_ = 0
                sub_sub_sub_schedule_end_ = 0
                sub_fcb = 0
                # 自制车次维度遍历
                for a in range(len(zz_n_start_time[i])):
                    # fcb表示是否排入该车次，0-1变量
                    fcb = model.NewBoolVar('fcb_%d_%d_%d_%d' % (i, j, k, a))
                    # 累加排入车次的开始时间
                    sub_sub_sub_schedule_start_ += fcb * zz_n_start_time[i][a]
                    # 累加排入车次的结束时间
                    sub_sub_sub_schedule_end_ += fcb * zz_n_d_list[i][a]
                    # 累计所选择的车次数量
                    sub_fcb += fcb
                # 每辆车只能选择一个开始时间
                model.Add(sub_fcb == 1)
                model.Add(sub_sub_sub_schedule_start == sub_sub_sub_schedule_start_)
                model.Add(sub_sub_sub_schedule_end == sub_sub_sub_schedule_end_)
                sub_sub_schedule_start.append(sub_sub_sub_schedule_start)
                sub_sub_schedule_end.append(sub_sub_sub_schedule_end)
            sub_schedule_start.append(sub_sub_schedule_start)
            sub_schedule_end.append(sub_sub_schedule_end)
        schedule_start.append(sub_schedule_start)
        schedule_end.append(sub_schedule_end)

    if (is_splitting_car == False):
        max_time = 999999999

    # 分别获取自制和ems各个交付对象件箱总量，不计算栈板转件箱的数量
    zz_total_cargo_num = get_cargo_num_(job_zz_data, job_zz_type)
    ems_total_cargo_num = get_cargo_num_(job_ems_data, job_ems_type)

    # 对速度进行打折处理
    floor_speed_map_integer = {}
    for v in floor_speed_map:
        # 求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度
        floor_speed_map_integer[v] = int(floor_speed_map[v] * dis * 10000)

    # 通道数的累加，相当于y轴，不能直接使用通道数，不然会重叠
    port_num_sum = {}
    sub_port_num_sum = 0
    for floor_port_num in (floor_port_num_map):
        port_num_sum[floor_port_num] = sub_port_num_sum
        sub_port_num_sum += floor_port_num_map[floor_port_num]

    # 用于累计最大通道数
    rs_delivery_count = {}
    for v in floor_speed_map:
        rs_delivery_count[v] = []
    # 统计每个楼层的数量
    num_deliveree = {}
    for v in floor_speed_map:
        # 求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度
        num_deliveree[v] = 0


    for i in range(len(job_zz_data)):
        num_deliveree[zz_floor[i]]+=1
    for i in range(len(job_ems_data)):
        num_deliveree[ems_floor[i]]+=1

    total_C_list = []
    bool_sub_job_list = []
    job_p_list = []
    x_intervals = []
    y_intervals = []
    solution_x_total_zz = []
    solution_bool_sub_job_zz = []
    solution_bool_C_zz = []
    solution_bool_C_N_zz = []
    solution_x_total_ems = []
    solution_bool_sub_job_ems = []
    solution_bool_C_ems = []
    de = []
    min_end_time = []         #时间靠前的目标参数累计
    rs_c = []
    total_bb = 0
    total_bbb = 0
    len_zz = len(job_zz_data)
    len_ems = len(job_ems_data)

    # 自制交付对象维度遍历
    for i in range(len(job_zz_data)):
        # 该厂家的车是否全部排完
        j_b = model.NewBoolVar('%d' % i)
        total_bb += j_b
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        bool_sub_ssub_job = []

        c_num_occupy = {}
        for port_num in floor_port_num_map:
            c_num_occupy[port_num] = [[] for _ in range(floor_port_num_map[port_num])]
        c_occupy_s = {}
        for j, port_num in enumerate(floor_port_num_map):
            c_occupy_s[port_num] = [model.NewIntVar(0, 100, 'p_e_%d%d' % (j, k)) for k in
                                    range(floor_port_num_map[port_num])]
        c_occupy = {}
        for j, port_num in enumerate(floor_port_num_map):
            c_occupy[port_num] = [model.NewBoolVar('ocp_%d%d' % (j, k)) for k in range(floor_port_num_map[port_num])]

        # 订单层级的遍历
        for j in range(len(job_zz_data[i])):
            # 订单是否完成
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))
            bool_sub_job.append(j_sub_b)
            u_bool_sub_sub_job = []
            u_job_p_sub_sub = []
            u_sub_C_list = []
            u_bool_sub_job_se = []
            # 车辆层级遍历
            for k in range(len(job_zz_data[i][j])):
                # 车辆是否排入
                u_j_sub_b_se = model.NewBoolVar('%d_%d_%d' % (i, j, k))
                u_bool_sub_job_se.append(u_j_sub_b_se)
                bool_sub_sub_job = []
                job_p_sub_sub = []
                sub_C_list = []
                # 车内部货物类型层级遍历（件箱、栈板）
                for p in range(len(job_zz_data[i][j][k])):
                    # 货物是否被分配通道并在交期内处理
                    j_sub_sub_b = model.NewBoolVar('%d_%d_%d_%d' % (i, j, k, p))
                    bool_sub_sub_job.append(j_sub_sub_b)
                    total_bbb += j_sub_sub_b
                    sub_sub_c_list = []
                    sub_sub_p_list = []
                    # 货物开始处理时间变量
                    j_sub_p_s = model.NewIntVar(0, max_time,
                                                'p_s_%d_%d_%d_%d' % (i, j, k, p))
                    # 货物结束处理时间变量
                    j_sub_p_e = model.NewIntVar(0, max_time,
                                                'p_e_%d_%d_%d_%d' % (i, j, k, p))
                    # 用于车辆时间间隔的变量
                    j_sub_p_e_1 = model.NewIntVar(0, max_time,
                                                  'p_e1_%d_%d_%d_%d' % (i, j, k, p))

                    s_set = []
                    for u in range(len(work_time_list)):
                        s = model.NewBoolVar('d')
                        s_set.append(s)
                        model.Add(j_sub_p_s >= work_time_list[u][0]).OnlyEnforceIf(s)
                        model.Add(j_sub_p_e <= work_time_list[u][1]).OnlyEnforceIf(s)
                    model.Add(sum(s_set) == 1)

                    min_end_time.append(j_sub_p_e)
                    # 交期是否满足的变量
                    due_data_d = model.NewBoolVar('due_data_d')
                    # 是否分配通道的变量
                    c_d = model.NewBoolVar('c_d')
                    model.Add(j_sub_p_s >= schedule_start[i][j][k])
                    model.Add(j_sub_p_e >= schedule_start[i][j][k])
                    model.Add(j_sub_p_e_1 >= schedule_start[i][j][k])
                    # 交期约束
                    model.Add(j_sub_p_e <= schedule_end[i][j][k]).OnlyEnforceIf(due_data_d)
                    model.Add(j_sub_p_e > schedule_end[i][j][k]).OnlyEnforceIf(due_data_d.Not())

                    s_set = []
                    for u in range(len(work_time_list)):
                        s = model.NewBoolVar('d')
                        s_set.append(s)
                        model.Add(j_sub_p_s >= work_time_list[u][0]).OnlyEnforceIf(s)
                        model.Add(j_sub_p_e <= work_time_list[u][1]).OnlyEnforceIf(s)
                    model.Add(sum(s_set) == 1)

                    sub_sub_p_list.append(j_sub_p_s)
                    sub_sub_p_list.append(j_sub_p_e)
                    sub_sub_p_list.append(j_sub_p_e_1)
                    job_p_sub_sub.append(sub_sub_p_list)
                    # 根据货物类型来查询通道
                    if job_zz_type[i][j][k][p] == 0:
                        for v in range(floor_port_num_map['plt']):  # 遍历通道
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, 7))
                            sub_sub_c_list.append(b)
                    else:
                        # 自制件箱的通道有些特殊，自制的通道分为去一楼的和去负一楼的，一楼的通道坏了，现在和EMS的通道共享
                        for m in range(floor_port_num_map[zz_floor[i]]):
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                            sub_sub_c_list.append(b)
                            c_num_occupy[zz_floor[i]][m].append(b)

                    model.Add(sum(sub_sub_c_list) <= job_zz_data[i][j][k][p])
                    model.Add(sum(sub_sub_c_list) > 0).OnlyEnforceIf(c_d)  # 分配通道，c_d为1
                    model.Add(sum(sub_sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
                    model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_sub_b)  # 交期通道两个全满足，货物进去
                    model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_sub_b.Not())
                    sub_C_list.append(sub_sub_c_list)
                u_job_p_sub_sub.append(job_p_sub_sub)
                u_sub_C_list.append(sub_C_list)
                u_bool_sub_sub_job.append(bool_sub_sub_job)
                model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(
                    u_j_sub_b_se)  # 件箱和栈板全部排入或件箱、栈板排入就代表车排入了
                model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(u_j_sub_b_se.Not())

            model.Add(sum(u_bool_sub_job_se) == len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b)  # 车全排入了，就代表订单完成了
            model.Add(sum(u_bool_sub_job_se) < len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b.Not())

            C_list.append(u_sub_C_list)
            bool_sub_ssub_job.append(u_bool_sub_sub_job)
            job_p_sub.append(u_job_p_sub_sub)


        if zz_total_cargo_num[i] > 0:
            [model.Add(c_occupy_s[zz_floor[i]][v] == sum(c_num_occupy[zz_floor[i]][v])) for v in
             range(len(c_occupy_s[zz_floor[i]]))]
            for v in range(len(c_occupy[zz_floor[i]])):
                model.Add(c_occupy_s[zz_floor[i]][v] > 0).OnlyEnforceIf(c_occupy[zz_floor[i]][v])
                model.Add(c_occupy_s[zz_floor[i]][v] <= 0).OnlyEnforceIf(c_occupy[zz_floor[i]][v].Not())

            for port_assignment_idx in range(len(port_assignment_map[zz_floor[i]]) - 1):
                if zz_total_cargo_num[i] >= port_assignment_map[zz_floor[i]][port_assignment_idx][1] and zz_total_cargo_num[
                    i] <= port_assignment_map[zz_floor[i]][port_assignment_idx + 1][1]:
                    model.Add(sum(c_occupy[zz_floor[i]]) == port_assignment_map[zz_floor[i]][port_assignment_idx][0])

        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)  # 所有订单完成了，厂家完成了
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())

        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_ssub_job)
        job_p_list.append(job_p_sub)

    for i in range(len(job_ems_data)):  # 厂家层级遍历
        ts = ems_data_end_start[i]
        j_b = model.NewBoolVar('%d' % i)  # 该厂家的车是否全部排完
        total_bb += j_b
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        bool_sub_ssub_job = []

        c_num_occupy = {}
        for port_num in floor_port_num_map:
            c_num_occupy[port_num] = [[] for _ in range(floor_port_num_map[port_num])]
        c_occupy_s = {}
        for j,port_num in enumerate(floor_port_num_map):
            c_occupy_s[port_num] = [model.NewIntVar(0, 100, 'p_e_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]
        c_occupy = {}
        for j,port_num in enumerate(floor_port_num_map) :
            c_occupy[port_num] = [model.NewBoolVar('ocp_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]


        for j in range(len(job_ems_data[i])):  # 订单层级的遍历
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))  # 订单是否完成
            bool_sub_job.append(j_sub_b)
            u_bool_sub_sub_job = []
            u_job_p_sub_sub = []
            u_sub_C_list = []
            u_bool_sub_job_se = []


            for k in range(len(job_ems_data[i][j])):  # 车辆层级遍历
                u_j_sub_b_se = model.NewBoolVar('%d_%d_%d' % (i, j, k))
                u_bool_sub_job_se.append(u_j_sub_b_se)

                bool_sub_sub_job = []
                job_p_sub_sub = []
                sub_C_list = []
                for p in range(len(job_ems_data[i][j][k])):  # 车内部货物类型层级遍历（件箱、栈板）
                    j_sub_sub_b = model.NewBoolVar('%d_%d_%d_%d' % (i, j, k, p))  # 货物是否被分配通道并在交期内处理
                    bool_sub_sub_job.append(j_sub_sub_b)
                    total_bbb += j_sub_sub_b
                    sub_sub_c_list = []
                    sub_sub_p_list = []
                    j_sub_p_s = model.NewIntVar(ts, max_time, 'p_s_%d_%d_%d_%d' % (i+len_zz, j, k, p))  # 货物开始处理时间变量
                    j_sub_p_e = model.NewIntVar(ts, max_time, 'p_e_%d_%d_%d_%d' % (i+len_zz, j, k, p))  # 货物结束处理时间变量
                    j_sub_p_e_1 = model.NewIntVar(ts, max_time, 'p_e1_%d_%d_%d_%d' % (i+len_zz, j, k, p))  # 用于车辆时间间隔的变量

                    s_set = []
                    for u in range(len(work_time_list)):
                        s = model.NewBoolVar('d')
                        s_set.append(s)
                        model.Add(j_sub_p_s >= work_time_list[u][0]).OnlyEnforceIf(s)
                        model.Add(j_sub_p_e <= work_time_list[u][1]).OnlyEnforceIf(s)
                    model.Add(sum(s_set) == 1)

                    s_set = []                              #不能跨时间窗的约束
                    for u in range(len(work_time_list)):
                        s = model.NewBoolVar('d')
                        s_set.append(s)
                        model.Add(j_sub_p_s >= work_time_list[u][0]).OnlyEnforceIf(s)
                        model.Add(j_sub_p_e <= work_time_list[u][1]).OnlyEnforceIf(s)
                    model.Add(sum(s_set) == 1)

                    min_end_time.append(j_sub_p_e)
                    due_data_d = model.NewBoolVar('due_data_d')  # 交期是否满足的变量
                    c_d = model.NewBoolVar('c_d')  # 是否分配通道的变量
                    model.Add(j_sub_p_e <= d_ems_list[i]).OnlyEnforceIf(due_data_d)  # 交期约束
                    model.Add(j_sub_p_e > d_ems_list[i]).OnlyEnforceIf(due_data_d.Not())  # 交期约束
                    sub_sub_p_list.append(j_sub_p_s)
                    sub_sub_p_list.append(j_sub_p_e)
                    sub_sub_p_list.append(j_sub_p_e_1)
                    job_p_sub_sub.append(sub_sub_p_list)


                    if job_ems_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                        for v in range(floor_port_num_map['plt']):  # 遍历通道
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i+len_zz, j, k, p, 7))
                            sub_sub_c_list.append(b)
                    else:
                        for m in range(floor_port_num_map[ems_floor[i]]):
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i+len_zz, j, k, p, m))
                            sub_sub_c_list.append(b)
                            c_num_occupy[ems_floor[i]][m].append(b)


                    model.Add(sum(sub_sub_c_list) <= job_ems_data[i][j][k][p])
                    model.Add(sum(sub_sub_c_list) > 0).OnlyEnforceIf(c_d)  # 分配通道，c_d为1
                    model.Add(sum(sub_sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
                    model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_sub_b)  # 交期通道两个全满足，货物进去
                    model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_sub_b.Not())
                    sub_C_list.append(sub_sub_c_list)
                u_job_p_sub_sub.append(job_p_sub_sub)
                u_sub_C_list.append(sub_C_list)
                u_bool_sub_sub_job.append(bool_sub_sub_job)
                model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(
                    u_j_sub_b_se)  # 件箱和栈板全部排入或件箱、栈板排入就代表车排入了
                model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(u_j_sub_b_se.Not())


            model.Add(sum(u_bool_sub_job_se) == len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b)  # 车全排入了，就代表订单完成了
            model.Add(sum(u_bool_sub_job_se) < len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b.Not())

            C_list.append(u_sub_C_list)
            bool_sub_ssub_job.append(u_bool_sub_sub_job)
            job_p_sub.append(u_job_p_sub_sub)


        if ems_total_cargo_num[i] >0:
            [model.Add(c_occupy_s[ems_floor[i]][v] == sum(c_num_occupy[ems_floor[i]][v])) for v in range(len(c_occupy_s[ems_floor[i]]))]
            for v in range(len(c_occupy[ems_floor[i]])):
                model.Add(c_occupy_s[ems_floor[i]][v] > 0).OnlyEnforceIf(c_occupy[ems_floor[i]][v])
                model.Add(c_occupy_s[ems_floor[i]][v] <= 0).OnlyEnforceIf(c_occupy[ems_floor[i]][v].Not())
            # if (num_deliveree[ems_floor[i]]>=floor_port_num_map[ems_floor[i]]):
            #     model.Add(sum(c_occupy[ems_floor[i]]) == 1)
            # else:
            for port_assignment_idx in range(len(port_assignment_map[ems_floor[i]])-1):
                if ems_total_cargo_num[i] >= port_assignment_map[ems_floor[i]][port_assignment_idx][1] and ems_total_cargo_num[i]<= port_assignment_map[ems_floor[i]][port_assignment_idx+1][1]:
                    model.Add(sum(c_occupy[ems_floor[i]]) <= port_assignment_map[ems_floor[i]][port_assignment_idx][0])

        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)  # 所有订单完成了，厂家完成了
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())

        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_ssub_job)
        job_p_list.append(job_p_sub)



    # 接下来分配通达，并计算运输时间
    for i in range(len(job_zz_data)):  # 厂家层级遍历
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            x_tt_intervals = []
            for e in range(len(job_zz_data[i][j])):  # 车辆遍历
                ini = []
                cd = []
                mm_v = model.NewIntVar(0, max_time, 'p_e_%d_%d' % (i, j))
                if(is_splitting_car==False):
                    itv2 = model.NewIntVar(-999999999, 999999999, 'itv2_%d_%d_%d' % (i, j, e))
                    itv3 = model.NewIntVar(0, 999999999, 'itv3_%d_%d_%d' % (i, j, e))
                    itv4 = model.NewIntVar(0, 999999999, 'itv4_%d_%d_%d' % (i, j, e))
                    zz_itv = model.NewIntVar(0, 999999999, 'ems_itv_%d_%d_%d' % (i, j, e))
                for p in range(len(job_zz_data[i][j][e])):  # 货物类型遍历
                    total_interval = 0  # 速度总和的变量
                    if job_zz_type[i][j][e][p] == 1:  # 和EMS共享通道
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer[zz_floor[i]]
                    else:
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer['plt']
                    t_i = model.NewIntVar(1, 99999999, 't_i_%d' % j)
                    model.Add(t_i == total_interval + 1)  # 速度计算待处理
                    I = model.NewIntVar(0, 99999999, 'In_%d' % j)
                    model.AddDivisionEquality(I, job_zz_data[i][j][e][p] * 10000, t_i)
                    ini.append(job_p_list[i][j][e][p][0])
                    cd.append(I)

                    kk = 0
                    if job_zz_type[i][j][e][p] == 1:  # 件箱货物形态
                        for u in range(floor_port_num_map[zz_floor[i]]):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, u))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][u],
                                                                             'p_%d_%d_%d_%d' % (
                                                                                 i, j, p, u))
                            j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum[zz_floor[i]] + u, 1, y_end,
                                                                             total_C_list[i][j][e][p][u],
                                                                             'c_%d_%d_%d_%d' % (
                                                                                 i, j, p, u))

                            kk += 1
                            rs_c.append(j_sub_p_intervals)  # 最大容量约束
                            rs_delivery_count[zz_floor[i]].append(j_sub_p_intervals) # 最大自制通道约束
                            de.append(int(floor_speed_map_integer[zz_floor[i]]))
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)




                    else:  # 栈板货物形态

                        for u in range(floor_port_num_map['plt']):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'p_%d_%d_%d_%d' % (i, j, p, kk))

                            j_sub_c_intervals = model.NewOptionalIntervalVar(u+port_num_sum['plt'], 1, y_end,
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'c_%d_%d_%d_%d' % (i, j, p, kk))
                            kk += 1
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)

                if len(ini) == 2:  # 若一辆车有两种类型的货物
                    model.Add(ini[0] == ini[1])  # 限制开始处理时间相同
                    model.Add(bool_sub_job_list[i][j][e][0] == bool_sub_job_list[i][j][e][1])
                    I_v = model.NewIntVar(0, 99999999, 'p_e_%d_%d' % (i, j))
                    model.AddMaxEquality(I_v, cd)

                    if(is_splitting_car==False):
                        if len(interval_time) > 0:  # 实现真实间隔约束
                            real_time_bool_var = 0
                            for kt in range(len(interval_time)):
                                it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                                it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                                rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                                rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                                rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                                model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)  # 表示开始时间早于不连续区间的标志位
                                model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                                model.Add(mm_v >= work_time_list[kt + 1][0]).OnlyEnforceIf(rag12)  # 表示结束时间晚于不连续区间的标志位
                                model.Add(mm_v < work_time_list[kt + 1][0]).OnlyEnforceIf(rag12.Not())
                                model.Add(ini[0] + I_v < work_time_list[kt][1]).OnlyEnforceIf(
                                    rag13)  # 表示开始时间加上时间间隔早于不连续区间的标志位
                                model.Add(ini[0] + I_v >= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                                model.AddMultiplicationEquality(it_bool_val,
                                                                [rag11, rag12])  # 表示开始时间早于不连续区间的同时结束时间晚于不连续区间的标志位
                                model.AddMultiplicationEquality(it_bool_val2, [it_bool_val,
                                                                               rag13])  # 表示开始时间早于不连续区间、结束时间晚于不连续区间、开始时间加上时间间隔早于不连续区间的标志位
                                real_time_bool_var += it_bool_val2 * interval_time[kt]

                            model.Add(itv2 == int(zz_interval_time[i]) - real_time_bool_var)  # 若出跨时间间隔，则将这部分时间减去
                            model.AddMaxEquality(itv3, (0, itv2))  # 减完后的时间小于0则为0
                            model.Add(itv4 >= itv3)  # 真实时间间隔
                            model.Add(itv4 <= int(zz_interval_time[i]))
                            model.Add(zz_itv == I_v + itv4 + 1)
                            j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], zz_itv,
                                                                               mm_v,
                                                                               bool_sub_job_list[i][j][e][0],
                                                                               '%d_%d_I' % (i, j))  # 发车间隔时间变量
                        else:
                            j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                               I_v + int(zz_interval_time[i]) + 1,
                                                                               mm_v,
                                                                               bool_sub_job_list[i][j][e][0],
                                                                               '%d_%d_I' % (i, j))  # 发车间隔时间变量

                        x_tt_intervals.append(j_sub_p_I_intervals)


                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], I_v + int(zz_interval_time[i]) + 1, mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                        x_tt_intervals.append(j_sub_p_I_intervals)
                else:
                    if(is_splitting_car==False):
                        if len(interval_time) > 0:  # 实现真实间隔约束
                            real_time_bool_var = 0
                            for kt in range(len(interval_time)):
                                it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                                it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                                rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                                rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                                rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                                model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)  # 表示开始时间早于不连续区间的标志位
                                model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                                model.Add(mm_v >= work_time_list[kt][1]).OnlyEnforceIf(rag12)  # 表示结束时间晚于不连续区间的标志位
                                model.Add(mm_v < work_time_list[kt][1]).OnlyEnforceIf(rag12.Not())
                                model.Add(ini[0] + cd[0] < work_time_list[kt][1]).OnlyEnforceIf(
                                    rag13)  # 表示开始时间加上时间间隔早于不连续区间的标志位
                                model.Add(ini[0] + cd[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                                model.AddMultiplicationEquality(it_bool_val,
                                                                [rag11, rag12])  # 表示开始时间早于不连续区间的同时结束时间晚于不连续区间的标志位
                                model.AddMultiplicationEquality(it_bool_val2, [it_bool_val,
                                                                               rag13])  # 表示开始时间早于不连续区间、结束时间晚于不连续区间、开始时间加上时间间隔早于不连续区间的标志位
                                real_time_bool_var += it_bool_val2 * interval_time[kt]

                            model.Add(itv2 == int(zz_interval_time[i]) - real_time_bool_var)  # 若出跨时间间隔，则将这部分时间减去
                            model.AddMaxEquality(itv3, (0, itv2))  # 减完后的时间小于0则为0
                            model.Add(itv4 >= itv3)  # 真实时间间隔
                            model.Add(itv4 <= int(zz_interval_time[i]))
                            model.Add(zz_itv == cd[0] + itv4 + 1)
                            j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], zz_itv,
                                                                               mm_v,
                                                                               bool_sub_job_list[i][j][e][0],
                                                                               '%d_%d_I' % (i, j))  # 发车间隔时间变量
                        else:
                            j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                               cd[0] + int(zz_interval_time[i]) + 1,
                                                                               mm_v,
                                                                               bool_sub_job_list[i][j][e][0],
                                                                               '%d_%d_I' % (i, j))  # 发车间隔时间变量

                        x_tt_intervals.append(j_sub_p_I_intervals)
                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], cd[0] + int(zz_interval_time[i]) + 1,
                                                                           mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                        x_tt_intervals.append(j_sub_p_I_intervals)

            model.AddNoOverlap(x_tt_intervals)



    for i in range(len(job_ems_data)):  # 厂家层级遍历
        for j in range(len(job_ems_data[i])):  # 订单层级遍历
            x_tt_intervals = []
            for e in range(len(job_ems_data[i][j])):  # 车辆遍历
                ini = []
                cd = []
                mm_v = model.NewIntVar(0, 999999999, 'p_e_%d_%d_%d' % (i, j,e))
                itv2 = model.NewIntVar(-999999999, 999999999, 'itv2_%d_%d_%d' % (i, j, e))
                itv3 = model.NewIntVar(0, 999999999, 'itv3_%d_%d_%d' % (i, j, e))
                itv4 = model.NewIntVar(0, 999999999, 'itv4_%d_%d_%d' % (i, j, e))
                ems_itv = model.NewIntVar(0, 999999999, 'ems_itv_%d_%d_%d' % (i, j, e))
                for p in range(len(job_ems_data[i][j][e])):  # 货物类型遍历
                    total_interval = 0  # 速度总和的变量
                    if job_ems_type[i][j][e][p] == 1:  # 和EMS共享通道
                        for k in range(len(total_C_list[i+len_zz][j][e][p])):
                            total_interval += total_C_list[i+len_zz][j][e][p][k] * floor_speed_map_integer[ems_floor[i]]
                    else:
                        for k in range(len(total_C_list[i+len_zz][j][e][p])):  # 去负一楼
                            total_interval += total_C_list[i+len_zz][j][e][p][k] * floor_speed_map_integer['plt']
                    t_i = model.NewIntVar(1, 99999999, 't_i_%d' % j)
                    model.Add(t_i == total_interval + 1)  # 速度计算，待处理
                    I = model.NewIntVar(0, 99999999, 'In_%d' % j)
                    model.AddDivisionEquality(I, job_ems_data[i][j][e][p] * 10000, t_i)
                    ini.append(job_p_list[i+len_zz][j][e][p][0])
                    cd.append(I)

                    kk = 0
                    if job_ems_type[i][j][e][p] == 1:  # 件箱货物形态

                        for u in range(floor_port_num_map[ems_floor[i]]):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i+len_zz][j][e][p][0], I + 1,
                                                                             job_p_list[i+len_zz][j][e][p][1],
                                                                             total_C_list[i+len_zz][j][e][p][kk],
                                                                             'p_%d_%d_%d_%d' % (i, j, p, kk))
                            j_sub_c_intervals = model.NewOptionalIntervalVar(u+port_num_sum[ems_floor[i]], 1, y_end,
                                                                             total_C_list[i+len_zz][j][e][p][kk],
                                                                             'c_%d_%d_%d_%d' % (i, j, p, kk))
                            kk += 1
                            rs_c.append(j_sub_p_intervals)
                            rs_delivery_count[ems_floor[i]].append(j_sub_p_intervals) # 最大自制通道约束
                            de.append(int(floor_speed_map_integer[ems_floor[i]]))
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)

                    else:
                        for u in range(floor_port_num_map['plt']):
                                y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                                j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i+len_zz][j][e][p][0], I + 1,
                                                                                 job_p_list[i+len_zz][j][e][p][1],
                                                                                 total_C_list[i+len_zz][j][e][p][kk],
                                                                                 'p_%d_%d_%d_%d' % (i, j, p, kk))
                                j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum['plt'] + u, 1, y_end,
                                                                                 total_C_list[i+len_zz][j][e][p][kk],
                                                                                 'c_%d_%d_%d_%d' % (i, j, p, kk))
                                kk += 1
                                x_intervals.append(j_sub_p_intervals)
                                y_intervals.append(j_sub_c_intervals)

                if len(ini) == 2:  # 若一辆车有两种类型的货物
                    model.Add(ini[0] == ini[1])  # 限制开始处理时间相同
                    model.Add(bool_sub_job_list[i+len_zz][j][e][0] == bool_sub_job_list[i+len_zz][j][e][1])
                    I_v = model.NewIntVar(0, 99999999, 'p_e_%d_%d' % (i, j))
                    model.AddMaxEquality(I_v, cd)
                    #
                    if len(interval_time) > 0:  #实现真实间隔约束
                        real_time_bool_var = 0
                        for kt in range(len(interval_time)):
                            it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                            rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                            rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                            model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)  #表示开始时间早于不连续区间的标志位
                            model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                            model.Add(mm_v >= work_time_list[kt + 1][0]).OnlyEnforceIf(rag12)#表示结束时间晚于不连续区间的标志位
                            model.Add(mm_v < work_time_list[kt + 1][0]).OnlyEnforceIf(rag12.Not())
                            model.Add(ini[0] + I_v < work_time_list[kt][1]).OnlyEnforceIf(rag13) #表示开始时间加上时间间隔早于不连续区间的标志位
                            model.Add(ini[0] + I_v >= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                            model.AddMultiplicationEquality(it_bool_val, [rag11, rag12]) #表示开始时间早于不连续区间的同时结束时间晚于不连续区间的标志位
                            model.AddMultiplicationEquality(it_bool_val2, [it_bool_val, rag13])#表示开始时间早于不连续区间、结束时间晚于不连续区间、开始时间加上时间间隔早于不连续区间的标志位
                            real_time_bool_var += it_bool_val2 * interval_time[kt]

                        model.Add(itv2 == int(ems_interval_time[i]) - real_time_bool_var)  #若出跨时间间隔，则将这部分时间减去
                        model.AddMaxEquality(itv3, (0, itv2))                    #减完后的时间小于0则为0
                        model.Add(itv4 >= itv3)                                 #真实时间间隔
                        model.Add(itv4 <= int(ems_interval_time[i]))
                        model.Add(ems_itv == I_v + itv4 + 1)
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], ems_itv,
                                                                           mm_v,
                                                                           bool_sub_job_list[i+len_zz][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                           I_v + int(ems_interval_time[i]) + 1,
                                                                           mm_v,
                                                                           bool_sub_job_list[i+len_zz][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量

                    x_tt_intervals.append(j_sub_p_I_intervals)
                else:
                    if len(interval_time) > 0:  #实现真实间隔约束
                        real_time_bool_var = 0
                        for kt in range(len(interval_time)):
                            it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                            rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                            rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                            model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)  #表示开始时间早于不连续区间的标志位
                            model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                            model.Add(mm_v >= work_time_list[kt][1]).OnlyEnforceIf(rag12)#表示结束时间晚于不连续区间的标志位
                            model.Add(mm_v < work_time_list[kt][1]).OnlyEnforceIf(rag12.Not())
                            model.Add(ini[0] +cd[0] < work_time_list[kt][1]).OnlyEnforceIf(rag13) #表示开始时间加上时间间隔早于不连续区间的标志位
                            model.Add(ini[0] +cd[0]>= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                            model.AddMultiplicationEquality(it_bool_val, [rag11, rag12])#表示开始时间早于不连续区间的同时结束时间晚于不连续区间的标志位
                            model.AddMultiplicationEquality(it_bool_val2, [it_bool_val, rag13])#表示开始时间早于不连续区间、结束时间晚于不连续区间、开始时间加上时间间隔早于不连续区间的标志位
                            real_time_bool_var += it_bool_val2 * interval_time[kt]

                        model.Add(itv2 == int(ems_interval_time[i]) - real_time_bool_var)#若出跨时间间隔，则将这部分时间减去
                        model.AddMaxEquality(itv3, (0, itv2))#减完后的时间小于0则为0
                        model.Add(itv4 >= itv3)   #真实时间间隔
                        model.Add(itv4 <= int(ems_interval_time[i]))
                        model.Add(ems_itv == cd[0] + itv4 + 1)
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], ems_itv,
                                                                           mm_v,
                                                                           bool_sub_job_list[i+len_zz][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                           cd[0] + int(ems_interval_time[i]) + 1,
                                                                           mm_v,
                                                                           bool_sub_job_list[i+len_zz][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量

                    x_tt_intervals.append(j_sub_p_I_intervals)
            model.AddNoOverlap(x_tt_intervals)



    load_rate = []

    for i in range(len(job_zz_data)):  # 计算装载率
        sub_load_rate = []
        for j in range(len(job_zz_data[i])):
            for k in range(len(job_zz_data[i][j])):
                total_goods = 0
                for p in range(len(job_zz_data[i][j][k])):
                    if job_zz_type[i][j][k][p] == 0:
                        total_goods += job_zz_data[i][j][k][p] * zhuan_hua_zz[i]            #实际货物需乘转化系数
                    else:
                        total_goods += job_zz_data[i][j][k][p]
                sub_load_rate.append(total_goods / rong_liang_zz[i])             #装载率等于货物量除以容量
        load_rate.append(sub_load_rate)

    load_rate_index = []

    for i in range(len(load_rate)):
        sub_load_rate = sorted(enumerate(load_rate[i]), key=lambda x: x[1], reverse=True)
        sub_load_index = [ind for ind, _ in sub_load_rate]
        load_rate_index.append(sub_load_index)

    for i in range(len(load_rate_index)):  # 装载率高的优先排前面
        if len(load_rate_index[i]) > 1:
            for k in range(len(load_rate_index[i]) - 1):
                model.Add(
                    job_p_list[i][0][load_rate_index[i][k]][0][0] < job_p_list[i][0][load_rate_index[i][k + 1]][0][0])

    load_rate = []

    for i in range(len(job_ems_data)): #计算装载率
        sub_load_rate = []
        for j in range(len(job_ems_data[i])):
            for k in range(len(job_ems_data[i][j])):
                total_goods = 0
                for p in range(len(job_ems_data[i][j][k])):
                    if job_ems_type[i][j][k][p] == 0:
                        total_goods += job_ems_data[i][j][k][p] * zhuan_hua_EMS[i]
                    else:
                        total_goods += job_ems_data[i][j][k][p]
                sub_load_rate.append(total_goods / rong_liang_EMS[i])
        load_rate.append(sub_load_rate)

    load_rate_index = []

    for i in range(len(load_rate)):
        sub_load_rate = sorted(enumerate(load_rate[i]), key=lambda x: x[1], reverse=True)
        sub_load_index = [ind for ind, _ in sub_load_rate]
        load_rate_index.append(sub_load_index)

    for i in range(len(load_rate_index)):  # 装载率高的优先排前面
        if len(load_rate_index[i]) > 1:
            for k in range(len(load_rate_index[i]) - 1):
                model.Add(
                    job_p_list[i+len_zz][0][load_rate_index[i][k]][0][0] < job_p_list[i+len_zz][0][load_rate_index[i][k + 1]][0][0])



    de_delivery_count = {}
    for v in floor_speed_map:
        de_delivery_count[v] = [1] * len(rs_delivery_count[v])

    model.AddNoOverlap2D(x_intervals, y_intervals)             #x轴和y轴不重叠约束
    model.AddCumulative(rs_c, de, int(10000 * box_flow_value * dis))  # 件箱库流量约束

    for v in floor_speed_map:                      #流速约束
        if(len(de_delivery_count[v])>0):
            de_delivery_count[v] = [1] * len(rs_delivery_count[v])
            model.AddCumulative(rs_delivery_count[v], de_delivery_count[v] , floor_delivery_num_map[v])


    sorted_result_ems = sorted(enumerate(ems_priority), key=lambda x: x[1])         #对ems排序
    sorted_result_zz = sorted(enumerate(zz_priority), key=lambda x: x[1])             #对自制排序

    for v in floor_speed_map:            #优先级约束，每一层单独计算

        sub_ems_priority = []
        sub_zz_priority = []

        for i in range(len(zz_priority)):            #优先级约束，每一层单独计算
            if(zz_floor[i]==v):
                sub_zz_priority.append([copy.deepcopy(sorted_result_zz[i][1]),i])

        for i in range(len(ems_priority)):
            if(ems_floor[i]==v):
                sub_ems_priority.append([copy.deepcopy(sorted_result_ems[i][1]),i+len_zz])

        priority_all = sub_zz_priority + sub_ems_priority            #自制和ems的优先级混合计算

        priority_index = sorted(priority_all,key=lambda x: x[0])

        car_first_start_time = []
        for i in range(len(priority_index)):
            sub_car_first_start_time = []
            for j in range(len(job_p_list[priority_index[i][1]])):
                for k in range(len(job_p_list[priority_index[i][1]][j])):
                    sub_car_first_start_time.append(job_p_list[priority_index[i][1]][j][k][0][0])
            car_first_start_time.append(sub_car_first_start_time)
        #
        left = 0
        #
        for i in range(1, len(car_first_start_time)):

            if (priority_index[i][0] > priority_index[i - 1][0]):
                first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % i)
                next_first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % (i + 1))
                model.AddMinEquality(first_start_time, car_first_start_time[i-1])
                model.AddMinEquality(next_first_start_time, car_first_start_time[i])
                model.Add(first_start_time <= next_first_start_time)
                left = i
            elif (priority_index[i][0] == priority_index[i - 1][0]):
                first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % i)
                next_first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % (i + 1))
                model.AddMinEquality(first_start_time, car_first_start_time[left])
                model.AddMinEquality(next_first_start_time, car_first_start_time[i])
                model.Add(first_start_time <= next_first_start_time)


    model.Maximize(total_bbb)  # 最大化排进去的车
    solver = cp_model.CpSolver()  #获得求解器
    solver.parameters.num_search_workers = 8 #设定线程数
    solver.parameters.max_time_in_seconds = t #设定求解时间
    solver.parameters.random_seed = 0 #设定随机种子
    status1 = solver.Solve(model)  #求解第一个目标

    # 得到最终的解
    solution_find = False



    if status1 == cp_model.OPTIMAL or status1 == cp_model.FEASIBLE:
        model.Add(total_bbb == round(solver.ObjectiveValue()))
        # trgt = model.NewIntVar(0, 99999999,'target')
        # model.AddMaxEquality(trgt, min_end_time)
        # model.Minimize(trgt)
        model.Minimize(sum(min_end_time))        #最小化排车时间，让车排得更近
        status2 = solver.Solve(model)
        if status2 == cp_model.OPTIMAL or status2 == cp_model.FEASIBLE:
            solution_find = True
            if status1 == cp_model.OPTIMAL and status2 == cp_model.OPTIMAL:
                logger.info("时间窗模型求得最优解")
            elif (status1 == cp_model.FEASIBLE or status1 == cp_model.OPTIMAL) and (
                    status2 == cp_model.FEASIBLE or status2 == cp_model.OPTIMAL):
                logger.info("时间窗模型求得次优解")
            else:
                logger.info("时间窗模型无解,程序结束")
                # exit()
    if solution_find == False:
        logger.error("时间窗模型无解,程序结束")
        # exit()



    for i in range(len(job_zz_data)):  # 厂家层级遍历
        solu_x_sub = []
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            u_solu_x_sub = []
            for g in range(len(job_zz_data[i][j])):  # 车辆层级遍历
                so = []
                for k in range(len(job_zz_data[i][j][g])):  # 货物层级遍历
                    solution_x = []
                    if not solution_find:  # 无解则用0填充解
                        solution_x.append(0)
                        solution_x.append(0)
                    else:
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][0]))
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][1]))
                    so.append(solution_x)
                u_solu_x_sub.append(so)
            solu_x_sub.append(u_solu_x_sub)
        solution_x_total_zz.append(solu_x_sub)

    for i in range(len(job_zz_data)):  # 厂家层级遍历
        solu_bool_sub = []
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            u_solu_bool_sub = []
            for g in range(len(job_zz_data[i][j])):  # 车辆层级遍历
                so = []
                for k in range(len(job_zz_data[i][j][g])):  # 货物层级遍历
                    if not solution_find:  # 无解则用0填充最后解
                        so.append(0)
                    else:
                        so.append(solver.Value(bool_sub_job_list[i][j][g][k]))
                u_solu_bool_sub.append(so)
            solu_bool_sub.append(u_solu_bool_sub)
        solution_bool_sub_job_zz.append(solu_bool_sub)

    for i in range(len(job_zz_data)):  # 厂家层级遍历
        solu_C_sub = []
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            solu_C_sub_sub = []
            for e in range(len(job_zz_data[i][j])):  # 车辆层级遍历
                u_solu_C_sub_sub = []
                if len(job_zz_data[i][j][e]) == 2:
                    so = []
                    c_index_list = []
                    for p in range(len(job_zz_data[i][j][e])):  # 货物层级遍历
                        # so = []
                        if job_zz_type[i][j][e][p] == 1:
                            c_index_list.append(p)


                    for p in range(len(job_zz_data[i][j][e])):

                        if job_zz_type[i][j][e][p] == 0:
                            c_index_list.append(p)

                    for w in range(len(total_C_list[i][j][e][c_index_list[0]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[0]][w]))


                    for w in range(len(total_C_list[i][j][e][c_index_list[1]])):
                        if not solution_find:  # 无解则用0填充最后解
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[1]][w]))

                    u_solu_C_sub_sub.append(so)

                else:
                    so = []
                    if job_zz_type[i][j][e][0] == 1:  # 如果是件箱
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:  # 无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))

                        so = so + [0] * floor_port_num_map['plt']
                        u_solu_C_sub_sub.append(so)
                    else:  # 如果是栈板
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:  # 无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))

                        so = [0] * floor_port_num_map[zz_floor[i]] + so
                        u_solu_C_sub_sub.append(so)
                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C_zz.append(solu_C_sub)

    for i in range(len(job_zz_data)):  # 厂家层级遍历
        solu_C_sub = []
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            solu_C_sub_sub = []
            for e in range(len(job_zz_data[i][j])):  # 车辆层级遍历
                u_solu_C_sub_sub = []
                for p in range(len(job_zz_data[i][j][e])):  # 货物层级遍历
                    so = []
                    k = 0
                    if job_zz_type[i][j][e][p] == 1:
                        for w in range(len(total_C_list[i][j][e][p])):
                            if not solution_find:  # 无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][p][w]))

                    else:
                        for z in range(floor_port_num_map['plt']):
                            if not solution_find:  # 无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][p][k]))
                            k += 1

                    u_solu_C_sub_sub.append(so)
                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C_N_zz.append(solu_C_sub)

    for i in range(len(job_ems_data)):
        solu_x_sub = []
        for j in range(len(job_ems_data[i])):
            u_solu_x_sub = []
            for g in range(len(job_ems_data[i][j])):
                so = []
                for k in range(len(job_ems_data[i][j][g])):
                    solution_x = []
                    if not solution_find:
                        solution_x.append(0)
                        solution_x.append(0)
                    else:
                        solution_x.append(solver.Value(job_p_list[i+len_zz][j][g][k][0]))
                        solution_x.append(solver.Value(job_p_list[i+len_zz][j][g][k][1]))
                    so.append(solution_x)
                u_solu_x_sub.append(so)
            solu_x_sub.append(u_solu_x_sub)
        solution_x_total_ems.append(solu_x_sub)

    for i in range(len(job_ems_data)):
        solu_bool_sub = []
        for j in range(len(job_ems_data[i])):
            u_solu_bool_sub = []
            for g in range(len(job_ems_data[i][j])):
                so = []
                for k in range(len(job_ems_data[i][j][g])):
                    if not solution_find:
                        so.append(0)
                    else:
                        so.append(solver.Value(bool_sub_job_list[i+len_zz][j][g][k]))
                u_solu_bool_sub.append(so)
            solu_bool_sub.append(u_solu_bool_sub)
        solution_bool_sub_job_ems.append(solu_bool_sub)

    for i in range(len(job_ems_data)):
        solu_C_sub = []
        for j in range(len(job_ems_data[i])):
            solu_C_sub_sub = []
            for e in range(len(job_ems_data[i][j])):
                u_solu_C_sub_sub = []
                if len(job_ems_data[i][j][e]) == 2:
                    so = []
                    c_index_list = []
                    for p in range(len(job_ems_data[i][j][e])):
                        if job_ems_type[i][j][e][p] == 1:
                            c_index_list.append(p)

                    for p in range(len(job_ems_data[i][j][e])):
                        if job_ems_type[i][j][e][p] == 0:
                            c_index_list.append(p)

                    for w in range(len(total_C_list[i+len_zz][j][e][c_index_list[0]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i+len_zz][j][e][c_index_list[0]][w]))

                    for w in range(len(total_C_list[i+len_zz][j][e][c_index_list[1]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i+len_zz][j][e][c_index_list[1]][w]))

                    u_solu_C_sub_sub.append(so)

                else:
                    so = []
                    if job_ems_type[i][j][e][0] == 1:
                        for w in range(len(total_C_list[i+len_zz][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i+len_zz][j][e][0][w]))

                        so = so + [0] * floor_port_num_map['plt']
                        u_solu_C_sub_sub.append(so)
                    else:
                        for w in range(len(total_C_list[i+len_zz][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i+len_zz][j][e][0][w]))
                        so = [0] * floor_port_num_map[ems_floor[i]] + so
                        u_solu_C_sub_sub.append(so)

                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C_ems.append(solu_C_sub)


    car_time = []
    for i in range(len(job_zz_data)):
        sub_car_time = []
        for j in range(len(job_zz_data[i])):
            sub_sub_car_time = []
            for k in range(len(job_zz_data[i][j])):
                sub_sub_sub_car_time = []
                for a in range(len(job_zz_data[i][j][k])):
                    if not solution_find:
                        sub_sub_sub_car_time.append([0,0])
                    else:
                        if(solver.Value(schedule_start[i][j][k])!=0):
                            schedule_start_time = solver.Value(schedule_start[i][j][k])
                            schedule_end_time = solver.Value(schedule_end[i][j][k])
                            sub_sub_sub_car_time.append([ zz_begin_time[i][zz_n_start_time[i].index(schedule_start_time)],zz_end_time[i][zz_n_d_list[i].index(schedule_end_time)]])
                sub_sub_car_time.append(sub_sub_sub_car_time)
            sub_car_time.append(sub_sub_car_time)
        car_time.append(sub_car_time)


    return solution_x_total_zz, solution_bool_sub_job_zz, solution_bool_C_zz, solution_bool_C_N_zz, solution_x_total_ems, solution_bool_sub_job_ems, solution_bool_C_ems, car_time


def insert_solve_all(job_zz_data, job_zz_type, dis, zz_car_time, t, zz_interval_time,
    rong_liang_zz, zhuan_hua_zz, box_flow_value, zz_priority, max_time, floor_speed_map, is_splitting_car, floor_port_num_map, ems_floor, zz_floor, port_assignment_map, floor_delivery_num_map,
    job_ems_data, d_ems_list, job_ems_type, ems_data_end_start,
    ems_interval_time, rong_liang_EMS, zhuan_hua_EMS,
    ems_priority, work_time_list, interval_time,  ems_time_lock, ems_port_lock, ems_id_lock, zz_time_lock, zz_port_lock, zz_id_lock, zz_d1,zz_n_start_time, zz_n_d_list,zz_car_num,zz_begin_time,zz_end_time, logger):

    '''
    主函数，直接用这个就行
    :param  job_list:决策变量，表示某个订单详情放入该厂家的某辆车中的货物数量，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，该厂家的某辆车的货物数量
    :param  job_total:装车模型，记录每辆车装载的货物量
    :param dis:打折系数
    :param t:求解时间
    :param zz_interval_time:自制发车间隔时间
    :param fu_dong_EMS:对应于厂家的浮动系数，只有一个维度(EMS)
    :param fu_dong_zz:对应于厂家的浮动系数，只有一个维度(自制)
    :param rong_liang_EMS:对应于厂家的车辆容量，只有一个维度(EMS)
    :param rong_liang_zz:对应于厂家的车辆容量，只有一个维度(自制)
    :param zhuan_hua_EMS:对应于厂家的转换系数，只有一个维度(EMS)    :param insert_time   插入时间
    :param global_time   全局时间
    :param box_flow_value  流量限制
    :param ems_detail_add_date  ems订单生成时间
    :param zz_detail_add_date    自制订单生成时间
    :param is_splitting_car     是否分车
    :param ems_floor    ems楼层参数
    :param zz_floor    自制楼层参数
    :param floor_speed_map  楼层速度参数
    :param floor_port_num_map   楼层通道参数
    :param floor_delivery_num_map   楼层最大通道数参数
    :param port_assignment_map  每几个货物分配多少通道
    :param ems_priority ems优先级
    :param zz_priority 自制优先级
    :param max_time:最大时间
    :param job_ems_data 决策变量，表示某个订单详情放入该厂家的某辆车中的货物数量，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，该厂家的某辆车的货物数量
    :param d_ems_list   ems结束时间
    :param job_ems_type     ems类型
    :param ems_data_end_start   ems开始时间
    :param ems_time_lock    ems被锁住的车的时间
    :param ems_port_lock    ems被锁住的车的端口
    :param ems_id_lock      ems id 信息
    :param zz_time_lock     自制被锁住的车的时间
    :param zz_port_lock     自制被锁住的车的时间
    :param zz_id_lock       自制 id 信息
    '''
    # 创建cpModel实例
    model = cp_model.CpModel()

    schedule_start = []
    schedule_end = []
    for i in range(len(job_zz_data)):          #厂家层级遍历
        sub_schedule_start = []
        sub_schedule_end = []
        for j in range(len(job_zz_data[i])):            #订单层级遍历
            sub_sub_schedule_start = []
            sub_sub_schedule_end = []
            for k in range(len(job_zz_data[i][j])):         #订单详情层级遍历
                sub_sub_sub_schedule_start = model.NewIntVar(0, 99999999, 's_s_%d%d%d' % (i, j, k))
                sub_sub_sub_schedule_end = model.NewIntVar(0, 99999999, 's_s_%d%d%d' % (i, j, k))
                sub_sub_sub_schedule_start_ = 0
                sub_sub_sub_schedule_end_ = 0
                sub_fcb = 0
                for a in range(len(zz_n_start_time[i])):        #开始时间遍历
                    fcb = model.NewBoolVar('fcb_%d_%d_%d_%d' % (i, j, k, a))    #选择开始时间的参数
                    sub_sub_sub_schedule_start_ += fcb * zz_n_start_time[i][a]  #累加开始时间，因为只能选择一个时间段，所以该参数也是实际的开始时间
                    sub_sub_sub_schedule_end_ += fcb * zz_n_d_list[i][a]    #累加结束时间，因为只能选择一个时间段，所以该参数也是实际的结束时间
                    sub_fcb += fcb                                #累计所选择的时间段数量
                model.Add(sub_fcb == 1)                         #每辆车只能选择一个开始时间
                model.Add(sub_sub_sub_schedule_start == sub_sub_sub_schedule_start_)
                model.Add(sub_sub_sub_schedule_end == sub_sub_sub_schedule_end_)
                sub_sub_schedule_start.append(sub_sub_sub_schedule_start)
                sub_sub_schedule_end.append(sub_sub_sub_schedule_end)
            sub_schedule_start.append(sub_sub_schedule_start)
            sub_schedule_end.append(sub_sub_schedule_end)
        schedule_start.append(sub_schedule_start)
        schedule_end.append(sub_schedule_end)

    if (is_splitting_car == False):
        max_time = 999999999

    zz_total_cargo_num = get_cargo_num_(job_zz_data, job_zz_type)
    ems_total_cargo_num = get_cargo_num_(job_ems_data, job_ems_type)

    # 对速度进行折扣处理
    floor_speed_map_integer = {}
    for v in floor_speed_map:
        floor_speed_map_integer[v] = int(floor_speed_map[v] * dis * 10000)  # 求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    port_num_sum = {}       #通道数的累加，相当于y轴，不能直接使用通道数，不然会重叠
    sub_port_num_sum = 0
    for floor_port_num in (floor_port_num_map):
        port_num_sum[floor_port_num] = sub_port_num_sum
        sub_port_num_sum += floor_port_num_map[floor_port_num]

    rs_delivery_count = {}  #用于累计最大通道数
    for v in floor_speed_map:
        rs_delivery_count[v] = []

    num_deliveree = {}  #统计每个楼层的数量
    for v in floor_speed_map:
        num_deliveree[v] = 0#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    for i in range(len(job_zz_data)):
        num_deliveree[zz_floor[i]]+=1
    for i in range(len(job_ems_data)):
        num_deliveree[ems_floor[i]]+=1
    min_end_time = []       #时间靠前的目标参数累计
    # min_end_time = {}
    # for v in floor_speed_map:
    #     min_end_time[v] = []#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    total_C_list = []
    bool_sub_job_list = []
    job_p_list = []
    x_intervals = []
    y_intervals = []
    solution_x_total_zz = []
    solution_bool_sub_job_zz = []
    solution_bool_C_zz = []
    solution_bool_C_N_zz = []
    solution_x_total_ems = []
    solution_bool_sub_job_ems = []
    solution_bool_C_ems = []
    de = []

    rs_c = []
    # rs_zz_delivery_count = []
    # rs_ems_delivery_count = []
    total_bb = 0
    total_bbb = 0
    len_zz = len(job_zz_data)
    len_ems = len(job_ems_data)

    if bool(ems_time_lock):                         #如果ems存在锁车
        for i in range(len(ems_time_lock)):         #遍历所有锁车参数
            for k in range(len(ems_port_lock[i])):      #遍历锁车通道
                if k < len(ems_port_lock[i]) - floor_port_num_map['plt']:           #通道把件箱和栈板合在了一起，因此先算件箱
                    if ems_port_lock[i][k] == 1 and (int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0])) > 0:        #如果该通道存在锁车的情况，并且时间差大于0
                        x_s = model.NewConstant(int(ems_time_lock[i][0][0]))                                    #锁车的起始时间
                        ii = model.NewConstant(int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0]))       #锁车的时间间隔
                        x_e = model.NewConstant(int(ems_time_lock[i][0][1]))                #锁车的结束时间
                        y_s = model.NewConstant(port_num_sum[ems_floor[i]] + k)             #通道数
                        iii = model.NewConstant(1)
                        y_e = model.NewConstant(port_num_sum[ems_floor[i]] + k + 1)

                        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)      #可选x轴变量
                        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)     #可选y轴变量
                        x_intervals.append(x_ii)                                           #x轴累计
                        rs_delivery_count[ems_floor[ems_id_lock[i]]].append(x_ii)       #最大通道数累计
                        y_intervals.append(y_ii)                                        #y轴累计
                else:
                    if ems_port_lock[i][k] == 1:                                        #
                        if len(ems_time_lock[i])  == 2:                                 #同时存在件箱和栈板
                            if (int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0])) > 0:
                                x_s = model.NewConstant(int(ems_time_lock[i][1][0]))
                                ii = model.NewConstant(int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0]))
                                x_e = model.NewConstant(int(ems_time_lock[i][1][1]))
                                y_s = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)

                        else:
                            if (int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0])) > 0:
                                x_s = model.NewConstant(int(ems_time_lock[i][0][0]))
                                ii = model.NewConstant(int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0]))
                                x_e = model.NewConstant(int(ems_time_lock[i][0][1]))
                                y_s = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)
    #
    if bool(zz_time_lock):           #如果自制存在锁车
        for i in range(len(zz_time_lock)):      #遍历所有锁车参数
            for j in range(len(zz_port_lock[i])):       #遍历锁车通道
                if j < len(zz_port_lock[i]) - floor_port_num_map['plt']:         #通道把件箱和栈板合在了一起，因此先算件箱
                    if zz_port_lock[i][j] == 1 and (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:            #如果该通道存在锁车的情况，并且时间差大于0
                        x_s = model.NewConstant(int(zz_time_lock[i][0][0]))                  #锁车的起始时间
                        ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))          #锁车的时间间隔
                        x_e = model.NewConstant(int(zz_time_lock[i][0][1]))         #锁车的结束时间
                        y_s = model.NewConstant(port_num_sum[zz_floor[i]] + j)          #通道数
                        iii = model.NewConstant(1)
                        y_e = model.NewConstant(port_num_sum[zz_floor[i]] + 1 + j)

                        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)        #可选x轴变量
                        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)        #可选y轴变量
                        rs_delivery_count[zz_floor[zz_id_lock[i]]].append(x_ii)             #最大通道数累计
                        x_intervals.append(x_ii)
                        y_intervals.append(y_ii)
                else:
                    if zz_port_lock[i][j] == 1:
                        if len(zz_time_lock[i]) == 2:            #同时存在件箱和栈板
                            if (int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0])) > 0:
                                x_s = model.NewConstant(int(zz_time_lock[i][1][0]))
                                ii = model.NewConstant(int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0]))
                                x_e = model.NewConstant(int(zz_time_lock[i][1][1]))
                                y_s = model.NewConstant(
                                    port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(
                                    port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)
                        else:
                            if (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
                                x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
                                ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
                                x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
                                y_s = model.NewConstant(
                                    port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(
                                    port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)


    for i in range(len(job_zz_data)):  # 厂家层级遍历
        j_b = model.NewBoolVar('%d' % i)  # 该厂家的车是否全部排完
        total_bb += j_b
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        bool_sub_ssub_job = []

        c_num_occupy = {}                #表示通道是否被占用的变量
        for port_num in floor_port_num_map:
            c_num_occupy[port_num] = [[] for _ in range(floor_port_num_map[port_num])]
        c_occupy_s = {}
        for j, port_num in enumerate(floor_port_num_map):
            c_occupy_s[port_num] = [model.NewIntVar(0, 100, 'p_e_%d%d' % (j, k)) for k in
                                    range(floor_port_num_map[port_num])]
        c_occupy = {}   #判断通道是否被占用的布尔变量
        for j, port_num in enumerate(floor_port_num_map):
            c_occupy[port_num] = [model.NewBoolVar('ocp_%d%d' % (j, k)) for k in range(floor_port_num_map[port_num])]


        for j in range(len(job_zz_data[i])):  # 订单层级的遍历
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))  # 订单是否完成
            bool_sub_job.append(j_sub_b)
            u_bool_sub_sub_job = []
            u_job_p_sub_sub = []
            u_sub_C_list = []
            u_bool_sub_job_se = []

            for k in range(len(job_zz_data[i][j])):  # 车辆层级遍历
                u_j_sub_b_se = model.NewBoolVar('%d_%d_%d' % (i, j, k))  # 车辆是否排入
                u_bool_sub_job_se.append(u_j_sub_b_se)
                bool_sub_sub_job = []
                job_p_sub_sub = []
                sub_C_list = []
                for p in range(len(job_zz_data[i][j][k])):  # 车内部货物类型层级遍历（件箱、栈板）
                    j_sub_sub_b = model.NewBoolVar('%d_%d_%d_%d' % (i, j, k, p))  # 货物是否被分配通道并在交期内处理
                    bool_sub_sub_job.append(j_sub_sub_b)
                    total_bbb += j_sub_sub_b
                    sub_sub_c_list = []
                    sub_sub_p_list = []
                    j_sub_p_s = model.NewIntVar(0, max_time,
                                                'p_s_%d_%d_%d_%d' % (i, j, k, p))  # 货物开始处理时间变量
                    j_sub_p_e = model.NewIntVar(0, max_time,
                                                'p_e_%d_%d_%d_%d' % (i, j, k, p))  # 货物结束处理时间变量
                    j_sub_p_e_1 = model.NewIntVar(0, max_time,
                                                  'p_e1_%d_%d_%d_%d' % (i, j, k, p))  # 用于车辆时间间隔的变量

                    # target = model.NewIntVar(0, max_time,
                    #                             'p_e_%d_%d_%d_%d' % (i, j, k, p))  # 货物结束处理时间变量
                    # model.AddMultiplicationEquality(target, [j_sub_p_e, j_sub_sub_b])
                    #
                    # min_end_time[zz_floor[i]].append(target)
                    min_end_time.append(j_sub_p_e)
                    due_data_d = model.NewBoolVar('due_data_d')  # 交期是否满足的变量
                    c_d = model.NewBoolVar('c_d')  # 是否分配通道的变量
                    model.Add(j_sub_p_s >= schedule_start[i][j][k])
                    model.Add(j_sub_p_e >= schedule_start[i][j][k])
                    model.Add(j_sub_p_e_1 >= schedule_start[i][j][k])
                    model.Add(j_sub_p_e <= schedule_end[i][j][k]).OnlyEnforceIf(due_data_d)  # 交期约束
                    model.Add(j_sub_p_e > schedule_end[i][j][k]).OnlyEnforceIf(due_data_d.Not())  # 交期约束
                    sub_sub_p_list.append(j_sub_p_s)
                    sub_sub_p_list.append(j_sub_p_e)
                    sub_sub_p_list.append(j_sub_p_e_1)
                    job_p_sub_sub.append(sub_sub_p_list)

                    if job_zz_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                        for v in range(floor_port_num_map['plt']):  # 遍历通道
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, 7))
                            sub_sub_c_list.append(b)
                    else:

                        for m in range(floor_port_num_map[zz_floor[i]]):
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                            sub_sub_c_list.append(b)
                            c_num_occupy[zz_floor[i]][m].append(b)

                    model.Add(sum(sub_sub_c_list) <= job_zz_data[i][j][k][p])
                    model.Add(sum(sub_sub_c_list) > 0).OnlyEnforceIf(c_d)  # 分配通道，c_d为1
                    model.Add(sum(sub_sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
                    model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_sub_b)  # 交期通道两个全满足，货物进去
                    model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_sub_b.Not())
                    sub_C_list.append(sub_sub_c_list)
                u_job_p_sub_sub.append(job_p_sub_sub)
                u_sub_C_list.append(sub_C_list)
                u_bool_sub_sub_job.append(bool_sub_sub_job)
                model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(
                    u_j_sub_b_se)  # 件箱和栈板全部排入或件箱、栈板排入就代表车排入了
                model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(u_j_sub_b_se.Not())

            model.Add(sum(u_bool_sub_job_se) == len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b)  # 车全排入了，就代表订单完成了
            model.Add(sum(u_bool_sub_job_se) < len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b.Not())

            C_list.append(u_sub_C_list)
            bool_sub_ssub_job.append(u_bool_sub_sub_job)
            job_p_sub.append(u_job_p_sub_sub)


        if zz_total_cargo_num[i] > 0:
            [model.Add(c_occupy_s[zz_floor[i]][v] == sum(c_num_occupy[zz_floor[i]][v])) for v in
             range(len(c_occupy_s[zz_floor[i]]))]
            for v in range(len(c_occupy[zz_floor[i]])):
                model.Add(c_occupy_s[zz_floor[i]][v] > 0).OnlyEnforceIf(c_occupy[zz_floor[i]][v])
                model.Add(c_occupy_s[zz_floor[i]][v] <= 0).OnlyEnforceIf(c_occupy[zz_floor[i]][v].Not())    #如果占用通道数量大于0则置1,如果占用通道数量为0则置0
            # if (num_deliveree[zz_floor[i]]>=floor_port_num_map[zz_floor[i]]):
            #     model.Add(sum(c_occupy[zz_floor[i]]) == 1)
            # else:
            for port_assignment_idx in range(len(port_assignment_map[zz_floor[i]]) - 1):        #遍历每个楼层的通道数量分配

                if zz_total_cargo_num[i] >= port_assignment_map[zz_floor[i]][port_assignment_idx][1] and zz_total_cargo_num[
                    i] <= port_assignment_map[zz_floor[i]][port_assignment_idx + 1][1]:     #如果通道数在范围内则通道数按照参数设定
                    model.Add(sum(c_occupy[zz_floor[i]]) == port_assignment_map[zz_floor[i]][port_assignment_idx][0])

        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)  # 所有订单完成了，厂家完成了
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())

        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_ssub_job)
        job_p_list.append(job_p_sub)

    for i in range(len(job_ems_data)):  # 厂家层级遍历
        ts = ems_data_end_start[i]
        j_b = model.NewBoolVar('%d' % i)  # 该厂家的车是否全部排完
        total_bb += j_b
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        bool_sub_ssub_job = []

        c_num_occupy = {}               #表示通道是否被占用的变量
        for port_num in floor_port_num_map:
            c_num_occupy[port_num] = [[] for _ in range(floor_port_num_map[port_num])]
        c_occupy_s = {}                  #判断通道是否被占用的布尔变量
        for j,port_num in enumerate(floor_port_num_map):
            c_occupy_s[port_num] = [model.NewIntVar(0, 100, 'p_e_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]
        c_occupy = {}
        for j,port_num in enumerate(floor_port_num_map) :
            c_occupy[port_num] = [model.NewBoolVar('ocp_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]


        for j in range(len(job_ems_data[i])):  # 订单层级的遍历
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))  # 订单是否完成
            bool_sub_job.append(j_sub_b)
            u_bool_sub_sub_job = []
            u_job_p_sub_sub = []
            u_sub_C_list = []
            u_bool_sub_job_se = []


            for k in range(len(job_ems_data[i][j])):  # 车辆层级遍历
                u_j_sub_b_se = model.NewBoolVar('%d_%d_%d' % (i, j, k))
                u_bool_sub_job_se.append(u_j_sub_b_se)

                bool_sub_sub_job = []
                job_p_sub_sub = []
                sub_C_list = []
                for p in range(len(job_ems_data[i][j][k])):  # 车内部货物类型层级遍历（件箱、栈板）
                    j_sub_sub_b = model.NewBoolVar('%d_%d_%d_%d' % (i, j, k, p))  # 货物是否被分配通道并在交期内处理
                    bool_sub_sub_job.append(j_sub_sub_b)
                    total_bbb += j_sub_sub_b
                    sub_sub_c_list = []
                    sub_sub_p_list = []
                    j_sub_p_s = model.NewIntVar(ts, max_time, 'p_s_%d_%d_%d_%d' % (i+len_zz, j, k, p))  # 货物开始处理时间变量
                    j_sub_p_e = model.NewIntVar(ts, max_time, 'p_e_%d_%d_%d_%d' % (i+len_zz, j, k, p))  # 货物结束处理时间变量
                    j_sub_p_e_1 = model.NewIntVar(ts, max_time, 'p_e1_%d_%d_%d_%d' % (i+len_zz, j, k, p))  # 用于车辆时间间隔的变量

                    # target = model.NewIntVar(0, max_time,
                    #                             'p_e_%d_%d_%d_%d' % (i, j, k, p))  # 货物结束处理时间变量
                    # model.AddMultiplicationEquality(target, [j_sub_p_e, j_sub_sub_b])
                    # min_end_time[ems_floor[i]].append(target)

                    min_end_time.append(j_sub_p_e)
                    due_data_d = model.NewBoolVar('due_data_d')  # 交期是否满足的变量
                    c_d = model.NewBoolVar('c_d')  # 是否分配通道的变量
                    model.Add(j_sub_p_e <= d_ems_list[i]).OnlyEnforceIf(due_data_d)  # 交期约束
                    model.Add(j_sub_p_e > d_ems_list[i]).OnlyEnforceIf(due_data_d.Not())  # 交期约束
                    sub_sub_p_list.append(j_sub_p_s)
                    sub_sub_p_list.append(j_sub_p_e)
                    sub_sub_p_list.append(j_sub_p_e_1)
                    job_p_sub_sub.append(sub_sub_p_list)


                    if job_ems_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                        for v in range(floor_port_num_map['plt']):  # 遍历通道
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i+len_zz, j, k, p, 7))
                            sub_sub_c_list.append(b)
                    else:
                        for m in range(floor_port_num_map[ems_floor[i]]):
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i+len_zz, j, k, p, m))
                            sub_sub_c_list.append(b)
                            c_num_occupy[ems_floor[i]][m].append(b)


                    model.Add(sum(sub_sub_c_list) <= job_ems_data[i][j][k][p])
                    model.Add(sum(sub_sub_c_list) > 0).OnlyEnforceIf(c_d)  # 分配通道，c_d为1
                    model.Add(sum(sub_sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
                    model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_sub_b)  # 交期通道两个全满足，货物进去
                    model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_sub_b.Not())
                    sub_C_list.append(sub_sub_c_list)
                u_job_p_sub_sub.append(job_p_sub_sub)
                u_sub_C_list.append(sub_C_list)
                u_bool_sub_sub_job.append(bool_sub_sub_job)
                model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(
                    u_j_sub_b_se)  # 件箱和栈板全部排入或件箱、栈板排入就代表车排入了
                model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(u_j_sub_b_se.Not())


            model.Add(sum(u_bool_sub_job_se) == len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b)  # 车全排入了，就代表订单完成了
            model.Add(sum(u_bool_sub_job_se) < len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b.Not())

            C_list.append(u_sub_C_list)
            bool_sub_ssub_job.append(u_bool_sub_sub_job)
            job_p_sub.append(u_job_p_sub_sub)


        if ems_total_cargo_num[i] >0:
            [model.Add(c_occupy_s[ems_floor[i]][v] == sum(c_num_occupy[ems_floor[i]][v])) for v in range(len(c_occupy_s[ems_floor[i]]))]
            for v in range(len(c_occupy[ems_floor[i]])):
                model.Add(c_occupy_s[ems_floor[i]][v] > 0).OnlyEnforceIf(c_occupy[ems_floor[i]][v])     #如果占用通道数量大于0则置1,如果占用通道数量为0则置0
                model.Add(c_occupy_s[ems_floor[i]][v] <= 0).OnlyEnforceIf(c_occupy[ems_floor[i]][v].Not())
            # if (num_deliveree[ems_floor[i]]>=floor_port_num_map[ems_floor[i]]):
            #     model.Add(sum(c_occupy[ems_floor[i]]) == 1)
            # else:
            for port_assignment_idx in range(len(port_assignment_map[ems_floor[i]])-1):  #遍历每个楼层的通道数量分配
                if ems_total_cargo_num[i] >= port_assignment_map[ems_floor[i]][port_assignment_idx][1] and ems_total_cargo_num[i]<= port_assignment_map[ems_floor[i]][port_assignment_idx+1][1]:
                    model.Add(sum(c_occupy[ems_floor[i]]) <= port_assignment_map[ems_floor[i]][port_assignment_idx][0])

        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)  # 所有订单完成了，厂家完成了
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())

        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_ssub_job)
        job_p_list.append(job_p_sub)




    # 接下来分配通达，并计算运输时间
    for i in range(len(job_zz_data)):  # 厂家层级遍历
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            x_tt_intervals = []
            for e in range(len(job_zz_data[i][j])):  # 车辆遍历
                ini = []
                cd = []
                mm_v = model.NewIntVar(0, max_time, 'p_e_%d_%d' % (i, j))
                for p in range(len(job_zz_data[i][j][e])):  # 货物类型遍历
                    total_interval = 0  # 速度总和的变量
                    if job_zz_type[i][j][e][p] == 1:  # 和EMS共享通道
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer[zz_floor[i]]
                    else:
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer['plt']
                    t_i = model.NewIntVar(1, 99999999, 't_i_%d' % j)
                    model.Add(t_i == total_interval + 1)  # 速度计算待处理
                    I = model.NewIntVar(0, 99999999, 'In_%d' % j)
                    model.AddDivisionEquality(I, job_zz_data[i][j][e][p] * 10000, t_i)
                    ini.append(job_p_list[i][j][e][p][0])
                    cd.append(I)

                    kk = 0
                    if job_zz_type[i][j][e][p] == 1:  # 件箱货物形态
                        for u in range(floor_port_num_map[zz_floor[i]]):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, u))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][u],
                                                                             'p_%d_%d_%d_%d' % (
                                                                                 i, j, p, u))
                            j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum[zz_floor[i]] + u, 1, y_end,
                                                                             total_C_list[i][j][e][p][u],
                                                                             'c_%d_%d_%d_%d' % (
                                                                                 i, j, p, u))

                            kk += 1
                            rs_c.append(j_sub_p_intervals)  # 最大容量约束
                            rs_delivery_count[zz_floor[i]].append(j_sub_p_intervals) # 最大自制通道约束
                            de.append(int(floor_speed_map_integer[zz_floor[i]]))
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)




                    else:  # 栈板货物形态

                        for u in range(floor_port_num_map['plt']):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'p_%d_%d_%d_%d' % (i, j, p, kk))

                            j_sub_c_intervals = model.NewOptionalIntervalVar(u+port_num_sum['plt'], 1, y_end,
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'c_%d_%d_%d_%d' % (i, j, p, kk))
                            kk += 1
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)

                if len(ini) == 2:  # 若一辆车有两种类型的货物
                    model.Add(ini[0] == ini[1])  # 限制开始处理时间相同
                    model.Add(bool_sub_job_list[i][j][e][0] == bool_sub_job_list[i][j][e][1])
                    I_v = model.NewIntVar(0, 99999999, 'p_e_%d_%d' % (i, j))
                    model.AddMaxEquality(I_v, cd)
                    j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], I_v + int(zz_interval_time[i]) + 1, mm_v,
                                                                       bool_sub_job_list[i][j][e][0],
                                                                       '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    x_tt_intervals.append(j_sub_p_I_intervals)
                else:
                    j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], cd[0] + int(zz_interval_time[i]) + 1,
                                                                       mm_v,
                                                                       bool_sub_job_list[i][j][e][0],
                                                                       '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    x_tt_intervals.append(j_sub_p_I_intervals)

            model.AddNoOverlap(x_tt_intervals)



    for i in range(len(job_ems_data)):  # 厂家层级遍历
        for j in range(len(job_ems_data[i])):  # 订单层级遍历
            x_tt_intervals = []
            for e in range(len(job_ems_data[i][j])):  # 车辆遍历
                ini = []
                cd = []
                mm_v = model.NewIntVar(0, 999999999, 'p_e_%d_%d_%d' % (i, j,e))
                itv2 = model.NewIntVar(-999999999, 999999999, 'itv2_%d_%d_%d' % (i, j, e))
                itv3 = model.NewIntVar(0, 999999999, 'itv3_%d_%d_%d' % (i, j, e))
                itv4 = model.NewIntVar(0, 999999999, 'itv4_%d_%d_%d' % (i, j, e))
                ems_itv = model.NewIntVar(0, 999999999, 'ems_itv_%d_%d_%d' % (i, j, e))
                for p in range(len(job_ems_data[i][j][e])):  # 货物类型遍历
                    total_interval = 0  # 速度总和的变量
                    if job_ems_type[i][j][e][p] == 1:  # 和EMS共享通道
                        for k in range(len(total_C_list[i+len_zz][j][e][p])):
                            total_interval += total_C_list[i+len_zz][j][e][p][k] * floor_speed_map_integer[ems_floor[i]]
                    else:
                        for k in range(len(total_C_list[i+len_zz][j][e][p])):  # 去负一楼
                            total_interval += total_C_list[i+len_zz][j][e][p][k] * floor_speed_map_integer['plt']
                    t_i = model.NewIntVar(1, 99999999, 't_i_%d' % j)
                    model.Add(t_i == total_interval + 1)  # 速度计算，待处理
                    I = model.NewIntVar(0, 99999999, 'In_%d' % j)
                    model.AddDivisionEquality(I, job_ems_data[i][j][e][p] * 10000, t_i)
                    ini.append(job_p_list[i+len_zz][j][e][p][0])
                    cd.append(I)

                    kk = 0
                    if job_ems_type[i][j][e][p] == 1:  # 件箱货物形态

                        for u in range(floor_port_num_map[ems_floor[i]]):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i+len_zz][j][e][p][0], I + 1,
                                                                             job_p_list[i+len_zz][j][e][p][1],
                                                                             total_C_list[i+len_zz][j][e][p][kk],
                                                                             'p_%d_%d_%d_%d' % (i, j, p, kk))
                            j_sub_c_intervals = model.NewOptionalIntervalVar(u+port_num_sum[ems_floor[i]], 1, y_end,
                                                                             total_C_list[i+len_zz][j][e][p][kk],
                                                                             'c_%d_%d_%d_%d' % (i, j, p, kk))
                            kk += 1
                            rs_c.append(j_sub_p_intervals)
                            rs_delivery_count[ems_floor[i]].append(j_sub_p_intervals) # 最大自制通道约束
                            de.append(int(floor_speed_map_integer[ems_floor[i]]))
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)

                    else:
                        for u in range(floor_port_num_map['plt']):
                                y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                                j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i+len_zz][j][e][p][0], I + 1,
                                                                                 job_p_list[i+len_zz][j][e][p][1],
                                                                                 total_C_list[i+len_zz][j][e][p][kk],
                                                                                 'p_%d_%d_%d_%d' % (i, j, p, kk))
                                j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum['plt'] + u, 1, y_end,
                                                                                 total_C_list[i+len_zz][j][e][p][kk],
                                                                                 'c_%d_%d_%d_%d' % (i, j, p, kk))
                                kk += 1
                                x_intervals.append(j_sub_p_intervals)
                                y_intervals.append(j_sub_c_intervals)

                if len(ini) == 2:  # 若一辆车有两种类型的货物
                    model.Add(ini[0] == ini[1])  # 限制开始处理时间相同
                    model.Add(bool_sub_job_list[i+len_zz][j][e][0] == bool_sub_job_list[i+len_zz][j][e][1])
                    I_v = model.NewIntVar(0, 99999999, 'p_e_%d_%d' % (i, j))
                    model.AddMaxEquality(I_v, cd)
                    #
                    if len(interval_time) > 0:  #实现真实间隔约束
                        real_time_bool_var = 0
                        for kt in range(len(interval_time)):
                            it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                            rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                            rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                            model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)  #表示开始时间早于不连续区间的标志位
                            model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                            model.Add(mm_v >= work_time_list[kt + 1][0]).OnlyEnforceIf(rag12)#表示结束时间晚于不连续区间的标志位
                            model.Add(mm_v < work_time_list[kt + 1][0]).OnlyEnforceIf(rag12.Not())
                            model.Add(ini[0] + I_v < work_time_list[kt][1]).OnlyEnforceIf(rag13) #表示开始时间加上时间间隔早于不连续区间的标志位
                            model.Add(ini[0] + I_v >= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                            model.AddMultiplicationEquality(it_bool_val, [rag11, rag12]) #表示开始时间早于不连续区间的同时结束时间晚于不连续区间的标志位
                            model.AddMultiplicationEquality(it_bool_val2, [it_bool_val, rag13])#表示开始时间早于不连续区间、结束时间晚于不连续区间、开始时间加上时间间隔早于不连续区间的标志位
                            real_time_bool_var += it_bool_val2 * interval_time[kt]

                        model.Add(itv2 == int(ems_interval_time[i]) - real_time_bool_var)  #若出跨时间间隔，则将这部分时间减去
                        model.AddMaxEquality(itv3, (0, itv2))                    #减完后的时间小于0则为0
                        model.Add(itv4 >= itv3)                                 #真实时间间隔
                        model.Add(itv4 <= int(ems_interval_time[i]))
                        model.Add(ems_itv == I_v + itv4 + 1)
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], ems_itv,
                                                                           mm_v,
                                                                           bool_sub_job_list[i+len_zz][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                           I_v + int(ems_interval_time[i]) + 1,
                                                                           mm_v,
                                                                           bool_sub_job_list[i+len_zz][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量

                    x_tt_intervals.append(j_sub_p_I_intervals)
                else:
                    if len(interval_time) > 0:  #实现真实间隔约束
                        real_time_bool_var = 0
                        for kt in range(len(interval_time)):
                            it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                            rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                            rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                            model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)  #表示开始时间早于不连续区间的标志位
                            model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                            model.Add(mm_v >= work_time_list[kt][1]).OnlyEnforceIf(rag12)#表示结束时间晚于不连续区间的标志位
                            model.Add(mm_v < work_time_list[kt][1]).OnlyEnforceIf(rag12.Not())
                            model.Add(ini[0] +cd[0] < work_time_list[kt][1]).OnlyEnforceIf(rag13) #表示开始时间加上时间间隔早于不连续区间的标志位
                            model.Add(ini[0] +cd[0]>= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                            model.AddMultiplicationEquality(it_bool_val, [rag11, rag12])#表示开始时间早于不连续区间的同时结束时间晚于不连续区间的标志位
                            model.AddMultiplicationEquality(it_bool_val2, [it_bool_val, rag13])#表示开始时间早于不连续区间、结束时间晚于不连续区间、开始时间加上时间间隔早于不连续区间的标志位
                            real_time_bool_var += it_bool_val2 * interval_time[kt]

                        model.Add(itv2 == int(ems_interval_time[i]) - real_time_bool_var)#若出跨时间间隔，则将这部分时间减去
                        model.AddMaxEquality(itv3, (0, itv2))#减完后的时间小于0则为0
                        model.Add(itv4 >= itv3)   #真实时间间隔
                        model.Add(itv4 <= int(ems_interval_time[i]))
                        model.Add(ems_itv == cd[0] + itv4 + 1)
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], ems_itv,
                                                                           mm_v,
                                                                           bool_sub_job_list[i+len_zz][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                           cd[0] + int(ems_interval_time[i]) + 1,
                                                                           mm_v,
                                                                           bool_sub_job_list[i+len_zz][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量

                    x_tt_intervals.append(j_sub_p_I_intervals)
            model.AddNoOverlap(x_tt_intervals)



    load_rate = []

    for i in range(len(job_zz_data)):  # 计算装载率
        sub_load_rate = []
        for j in range(len(job_zz_data[i])):
            for k in range(len(job_zz_data[i][j])):
                total_goods = 0
                for p in range(len(job_zz_data[i][j][k])):
                    if job_zz_type[i][j][k][p] == 0:
                        total_goods += job_zz_data[i][j][k][p] * zhuan_hua_zz[i]        #实际货物需乘转化系数
                    else:
                        total_goods += job_zz_data[i][j][k][p]
                sub_load_rate.append(total_goods / rong_liang_zz[i])                    #装载率等于货物量除以容量
        load_rate.append(sub_load_rate)

    load_rate_index = []

    for i in range(len(load_rate)):
        sub_load_rate = sorted(enumerate(load_rate[i]), key=lambda x: x[1], reverse=True)
        sub_load_index = [ind for ind, _ in sub_load_rate]
        load_rate_index.append(sub_load_index)

    for i in range(len(load_rate_index)):  # 装载率高的优先排前面
        if len(load_rate_index[i]) > 1:
            for k in range(len(load_rate_index[i]) - 1):
                model.Add(
                    job_p_list[i][0][load_rate_index[i][k]][0][0] < job_p_list[i][0][load_rate_index[i][k + 1]][0][0])

    load_rate = []

    for i in range(len(job_ems_data)): #计算装载率
        sub_load_rate = []
        for j in range(len(job_ems_data[i])):
            for k in range(len(job_ems_data[i][j])):
                total_goods = 0
                for p in range(len(job_ems_data[i][j][k])):
                    if job_ems_type[i][j][k][p] == 0:
                        total_goods += job_ems_data[i][j][k][p] * zhuan_hua_EMS[i]   #实际货物需乘转化系数
                    else:
                        total_goods += job_ems_data[i][j][k][p]
                sub_load_rate.append(total_goods / rong_liang_EMS[i])                #装载率等于货物量除以容量
        load_rate.append(sub_load_rate)

    load_rate_index = []

    for i in range(len(load_rate)):
        sub_load_rate = sorted(enumerate(load_rate[i]), key=lambda x: x[1], reverse=True)
        sub_load_index = [ind for ind, _ in sub_load_rate]
        load_rate_index.append(sub_load_index)

    for i in range(len(load_rate_index)):  # 装载率高的优先排前面
        if len(load_rate_index[i]) > 1:
            for k in range(len(load_rate_index[i]) - 1):
                model.Add(
                    job_p_list[i+len_zz][0][load_rate_index[i][k]][0][0] < job_p_list[i+len_zz][0][load_rate_index[i][k + 1]][0][0])

    # #

    de_delivery_count = {}
    for v in floor_speed_map:
        de_delivery_count[v] = [1] * len(rs_delivery_count[v])
    #
    model.AddNoOverlap2D(x_intervals, y_intervals)              #x轴和y轴不重叠约束
    model.AddCumulative(rs_c, de, int(10000 * box_flow_value * dis))  # 件箱库流量约束
    #
    for v in floor_speed_map:                                   #流速约束
        if(len(de_delivery_count[v])>0):
            de_delivery_count[v] = [1] * len(rs_delivery_count[v])
            model.AddCumulative(rs_delivery_count[v], de_delivery_count[v] , floor_delivery_num_map[v])


    sorted_result_ems = sorted(enumerate(ems_priority), key=lambda x: x[1])     #对ems排序
    sorted_result_zz = sorted(enumerate(zz_priority), key=lambda x: x[1])       #对自制排序

    # ems_result1 = []
    # ems_result2 = []
    # ems_result3 = []
    # for idx,i in enumerate(range(len(ems_floor))):
    #     if ems_floor[i] == 1:
    #         ems_result1.append(idx)
    #     if ems_floor[i] == 2:
    #         ems_result2.append(idx)
    #     if ems_floor[i] == 3:
    #         ems_result3.append(idx)

    for v in floor_speed_map:               #优先级约束，每一层单独计算

        sub_ems_priority = []
        sub_zz_priority = []

        for i in range(len(zz_priority)):                   #优先级约束，每一层单独计算
            if(zz_floor[i]==v):
                sub_zz_priority.append([copy.deepcopy(sorted_result_zz[i][1]),i])

        for i in range(len(ems_priority)):
            if(ems_floor[i]==v):
                sub_ems_priority.append([copy.deepcopy(sorted_result_ems[i][1]),i+len_zz])

        priority_all = sub_zz_priority + sub_ems_priority       #自制和ems的优先级混合计算

        priority_index = sorted(priority_all,key=lambda x: x[0])

        car_first_start_time = []
        for i in range(len(priority_index)):
            sub_car_first_start_time = []
            for j in range(len(job_p_list[priority_index[i][1]])):
                for k in range(len(job_p_list[priority_index[i][1]][j])):
                    sub_car_first_start_time.append(job_p_list[priority_index[i][1]][j][k][0][0])
            car_first_start_time.append(sub_car_first_start_time)
        #
        left = 0
        #
        for i in range(1, len(car_first_start_time)):

            if (priority_index[i][0] > priority_index[i - 1][0]):
                first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % i)
                next_first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % (i + 1))
                model.AddMinEquality(first_start_time, car_first_start_time[i-1])
                model.AddMinEquality(next_first_start_time, car_first_start_time[i])
                model.Add(first_start_time <= next_first_start_time)
                left = i
            elif (priority_index[i][0] == priority_index[i - 1][0]):
                first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % i)
                next_first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % (i + 1))
                model.AddMinEquality(first_start_time, car_first_start_time[left])
                model.AddMinEquality(next_first_start_time, car_first_start_time[i])
                model.Add(first_start_time <= next_first_start_time)


    model.Maximize(total_bbb)  # 最大化排进去的车
    solver = cp_model.CpSolver()            #获得求解器
    solver.parameters.num_search_workers = 8        #设定线程数
    solver.parameters.max_time_in_seconds = t       #设定求解时间
    solver.parameters.random_seed = 0       #设定随机种子
    status1 = solver.Solve(model)           #求解第一个目标

    # 得到最终的解
    solution_find = False

    if status1 == cp_model.OPTIMAL or status1 == cp_model.FEASIBLE:
        model.Add(total_bbb == round(solver.ObjectiveValue()))
        # trgt = []
        # for v in floor_speed_map:
        #     if(len(min_end_time[v])>0):
        #         sub_trgt = model.NewIntVar(0, 99999999,'target')
        #         model.AddMaxEquality(sub_trgt, min_end_time[v])
        #         trgt.append(sub_trgt)
        # model.Minimize(sum(trgt))
        model.Minimize(sum(min_end_time))       #最小化排车时间，让车排得更近
        status2 = solver.Solve(model)
        if status2 == cp_model.OPTIMAL or status2 == cp_model.FEASIBLE:
            solution_find = True
            if status1 == cp_model.OPTIMAL and status2 == cp_model.OPTIMAL:
                logger.info("时间窗模型求得最优解")
            elif (status1 == cp_model.FEASIBLE or status1 == cp_model.OPTIMAL) and (
                    status2 == cp_model.FEASIBLE or status2 == cp_model.OPTIMAL):
                logger.info("时间窗模型求得次优解")
            else:
                logger.info("时间窗模型无解,程序结束")
                # exit()
    if solution_find == False:
        logger.error("时间窗模型无解,程序结束")
        # exit()



    for i in range(len(job_zz_data)):  # 厂家层级遍历
        solu_x_sub = []
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            u_solu_x_sub = []
            for g in range(len(job_zz_data[i][j])):  # 车辆层级遍历
                so = []
                for k in range(len(job_zz_data[i][j][g])):  # 货物层级遍历
                    solution_x = []
                    if not solution_find:  # 无解则用0填充解
                        solution_x.append(0)
                        solution_x.append(0)
                    else:
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][0]))
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][1]))
                    so.append(solution_x)
                u_solu_x_sub.append(so)
            solu_x_sub.append(u_solu_x_sub)
        solution_x_total_zz.append(solu_x_sub)

    for i in range(len(job_zz_data)):  # 厂家层级遍历
        solu_bool_sub = []
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            u_solu_bool_sub = []
            for g in range(len(job_zz_data[i][j])):  # 车辆层级遍历
                so = []
                for k in range(len(job_zz_data[i][j][g])):  # 货物层级遍历
                    if not solution_find:  # 无解则用0填充最后解
                        so.append(0)
                    else:
                        so.append(solver.Value(bool_sub_job_list[i][j][g][k]))
                u_solu_bool_sub.append(so)
            solu_bool_sub.append(u_solu_bool_sub)
        solution_bool_sub_job_zz.append(solu_bool_sub)

    for i in range(len(job_zz_data)):  # 厂家层级遍历
        solu_C_sub = []
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            solu_C_sub_sub = []
            for e in range(len(job_zz_data[i][j])):  # 车辆层级遍历
                u_solu_C_sub_sub = []
                if len(job_zz_data[i][j][e]) == 2:
                    so = []
                    c_index_list = []
                    for p in range(len(job_zz_data[i][j][e])):  # 货物层级遍历
                        # so = []
                        if job_zz_type[i][j][e][p] == 1:
                            c_index_list.append(p)


                    for p in range(len(job_zz_data[i][j][e])):

                        if job_zz_type[i][j][e][p] == 0:
                            c_index_list.append(p)

                    for w in range(len(total_C_list[i][j][e][c_index_list[0]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[0]][w]))


                    for w in range(len(total_C_list[i][j][e][c_index_list[1]])):
                        if not solution_find:  # 无解则用0填充最后解
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[1]][w]))

                    u_solu_C_sub_sub.append(so)

                else:
                    so = []
                    if job_zz_type[i][j][e][0] == 1:  # 如果是件箱
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:  # 无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))

                        so = so + [0] * floor_port_num_map['plt']
                        u_solu_C_sub_sub.append(so)
                    else:  # 如果是栈板
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:  # 无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))

                        so = [0] * floor_port_num_map[zz_floor[i]] + so
                        u_solu_C_sub_sub.append(so)
                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C_zz.append(solu_C_sub)

    for i in range(len(job_zz_data)):  # 厂家层级遍历
        solu_C_sub = []
        for j in range(len(job_zz_data[i])):  # 订单层级遍历
            solu_C_sub_sub = []
            for e in range(len(job_zz_data[i][j])):  # 车辆层级遍历
                u_solu_C_sub_sub = []
                for p in range(len(job_zz_data[i][j][e])):  # 货物层级遍历
                    so = []
                    k = 0
                    if job_zz_type[i][j][e][p] == 1:
                        for w in range(len(total_C_list[i][j][e][p])):
                            if not solution_find:  # 无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][p][w]))

                    else:
                        for z in range(floor_port_num_map['plt']):
                            if not solution_find:  # 无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][p][k]))
                            k += 1

                    u_solu_C_sub_sub.append(so)
                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C_N_zz.append(solu_C_sub)

    for i in range(len(job_ems_data)):
        solu_x_sub = []
        for j in range(len(job_ems_data[i])):
            u_solu_x_sub = []
            for g in range(len(job_ems_data[i][j])):
                so = []
                for k in range(len(job_ems_data[i][j][g])):
                    solution_x = []
                    if not solution_find:
                        solution_x.append(0)
                        solution_x.append(0)
                    else:
                        solution_x.append(solver.Value(job_p_list[i+len_zz][j][g][k][0]))
                        solution_x.append(solver.Value(job_p_list[i+len_zz][j][g][k][1]))
                    so.append(solution_x)
                u_solu_x_sub.append(so)
            solu_x_sub.append(u_solu_x_sub)
        solution_x_total_ems.append(solu_x_sub)

    for i in range(len(job_ems_data)):
        solu_bool_sub = []
        for j in range(len(job_ems_data[i])):
            u_solu_bool_sub = []
            for g in range(len(job_ems_data[i][j])):
                so = []
                for k in range(len(job_ems_data[i][j][g])):
                    if not solution_find:
                        so.append(0)
                    else:
                        so.append(solver.Value(bool_sub_job_list[i+len_zz][j][g][k]))
                u_solu_bool_sub.append(so)
            solu_bool_sub.append(u_solu_bool_sub)
        solution_bool_sub_job_ems.append(solu_bool_sub)

    for i in range(len(job_ems_data)):
        solu_C_sub = []
        for j in range(len(job_ems_data[i])):
            solu_C_sub_sub = []
            for e in range(len(job_ems_data[i][j])):
                u_solu_C_sub_sub = []
                if len(job_ems_data[i][j][e]) == 2:
                    so = []
                    c_index_list = []
                    for p in range(len(job_ems_data[i][j][e])):
                        if job_ems_type[i][j][e][p] == 1:
                            c_index_list.append(p)

                    for p in range(len(job_ems_data[i][j][e])):
                        if job_ems_type[i][j][e][p] == 0:
                            c_index_list.append(p)

                    for w in range(len(total_C_list[i+len_zz][j][e][c_index_list[0]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i+len_zz][j][e][c_index_list[0]][w]))

                    for w in range(len(total_C_list[i+len_zz][j][e][c_index_list[1]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i+len_zz][j][e][c_index_list[1]][w]))

                    u_solu_C_sub_sub.append(so)

                else:
                    so = []
                    if job_ems_type[i][j][e][0] == 1:
                        for w in range(len(total_C_list[i+len_zz][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i+len_zz][j][e][0][w]))

                        so = so + [0] * floor_port_num_map['plt']
                        u_solu_C_sub_sub.append(so)
                    else:
                        for w in range(len(total_C_list[i+len_zz][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i+len_zz][j][e][0][w]))
                        so = [0] * floor_port_num_map[ems_floor[i]] + so
                        u_solu_C_sub_sub.append(so)

                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C_ems.append(solu_C_sub)


    car_time = []
    for i in range(len(job_zz_data)):
        sub_car_time = []
        for j in range(len(job_zz_data[i])):
            sub_sub_car_time = []
            for k in range(len(job_zz_data[i][j])):
                sub_sub_sub_car_time = []
                for a in range(len(job_zz_data[i][j][k])):
                    if not solution_find:
                        sub_sub_sub_car_time.append([0,0])
                    else:
                        if(solver.Value(schedule_start[i][j][k])!=0):
                            schedule_start_time = solver.Value(schedule_start[i][j][k])
                            schedule_end_time = solver.Value(schedule_end[i][j][k])
                            sub_sub_sub_car_time.append([zz_begin_time[i][zz_n_start_time[i].index(schedule_start_time)],zz_end_time[i][zz_n_d_list[i].index(schedule_end_time)]])
                sub_sub_car_time.append(sub_sub_sub_car_time)
            sub_car_time.append(sub_sub_car_time)
        car_time.append(sub_car_time)

    return solution_x_total_zz, solution_bool_sub_job_zz, solution_bool_C_zz, solution_bool_C_N_zz, solution_x_total_ems, solution_bool_sub_job_ems, solution_bool_C_ems, car_time


def time_window_process_se(t, zz_begin_time, zz_end_time):
    '''
    时间窗的时间可能不是连续的，我们需要将不连续的时间去掉，使其变的连续，方便时间窗的计算，就像这样[[540, 740],[740, 940],[1140, 1340]] -> [[540, 740],[740, 940],[940, 1140]]
    将时间向前移，在那个需要移动的时间窗范围内的时间也需要移动，在时间窗模型计算完后，再把解进行还原
    这个函数处理了自制发车表的开始时间和结束时间
    :param t: 时间窗
    :param zz_begin_time: 自制发车表的开始时间
    :param zz_end_time: 自制发车表的结束时间
    :return: zz_begin_time 时间窗连续化后的自制发车表的开始时间
    :return: zz_end_time 时间窗连续化后的自制发车表的结束时间
    '''

    new_zz_begin_time = copy.deepcopy(zz_begin_time)  #自制开始时间
    new_zz_end_time = copy.deepcopy(zz_end_time)    #自制结束时间
    n_t = []
    check_work = []

    if len(t) > 1:                 #如果时间窗长度大于1
        for i in range(len(t)):
            if i != 0:
                if t[i][0] - t[i - 1][1] > 0:        #如果两个时间窗之间存在时间间隔，则把时间间隔加入n_t,但是在check_work中标记为0，表示不工作，再把正常的时间窗加入n_t，表示工作
                    n_t.append([t[i - 1][1], t[i][0]])
                    n_t.append([t[i][0], t[i][1]])
                    check_work.append(0)
                    check_work.append(1)
                else:                                 #如果两个时间窗之间不存在时间间隔，把正常的时间窗加入n_t，表示工作
                    n_t.append([t[i][0], t[i][1]])
                    check_work.append(1)
            else:
                n_t.append([t[i][0], t[i][1]])
                check_work.append(1)
    else:
        n_t.append([t[0][0], t[0][1]])               #加入第一个时间窗
        check_work.append(1)

    for i in range(len(new_zz_begin_time)):
        for j in range(len(new_zz_begin_time[i])):
            no_work_time = 0
            for k in range(len(n_t)):
                if new_zz_begin_time[i][j] >= n_t[k][0] and new_zz_begin_time[i][j] <= n_t[k][1]:      #如果开始时间在n_t内部，减去没有工作的时间
                    if check_work[k] == 1:
                        new_zz_begin_time[i][j] = math.floor(new_zz_begin_time[i][j] - no_work_time)     #排除可能存在的小数影响
                        break
                    else:
                        new_zz_begin_time[i][j] = math.floor(
                            new_zz_begin_time[i][j] - no_work_time - (new_zz_begin_time[i][j] - n_t[k][0]))          #排除可能存在的小数影响
                        break
                else:
                    if check_work[k] == 0:                           #如果check_work为0，则把这段时间间隔累计到no_work_time上
                        no_work_time += n_t[k][1] - n_t[k][0]

    for i in range(len(new_zz_end_time)):
        for j in range(len(new_zz_end_time[i])):
            no_work_time = 0
            for k in range(len(n_t)):
                if new_zz_end_time[i][j] >= n_t[k][0] and new_zz_end_time[i][j] <= n_t[k][1]:         #如果开始时间在n_t内部，减去没有工作的时间
                    if check_work[k] == 1:
                        new_zz_end_time[i][j] = math.ceil(new_zz_end_time[i][j] - no_work_time)      #排除可能存在的小数影响
                        break
                    else:
                        new_zz_end_time[i][j] = math.ceil(
                            new_zz_end_time[i][j] - no_work_time - (new_zz_end_time[i][j] - n_t[k][0]))      #排除可能存在的小数影响
                        break
                else:
                    if check_work[k] == 0:
                        no_work_time += n_t[k][1] - n_t[k][0]

    return new_zz_begin_time, new_zz_end_time


def time_window_process(t, start_time, d_list):
    '''
    时间窗连续预处理，时间窗的时间可能不是连续的，我们需要将不连续的时间去掉，使其变的连续，方便时间窗的计算，就像这样[[540, 740],[740, 940],[1140, 1340]] -> [[540, 740],[740, 940],[940, 1140]]
    将时间向前移，在那个需要移动的时间窗范围内的时间也需要移动，在时间窗模型计算完后，再把解进行还原
    这个函数处理了EMS的开始时间和结束时间
    :param t: 时间窗
    :param start_time: 需要处理的开始时间
    :param d_list: 需要处理的结束时间
    :return: n_start_time 连续时间窗的开始时间
    :return: n_d_list 连续时间窗的结束时间
    :return: no_work_time_re 连续化后的时间窗
    :return:  work_time_list 连续化后的时间窗之间的不工作时间段
    '''
    interval_time = []
    for i in range(len(t)-1):               #获取时间窗的时间间隔
        interval_time.append(t[i+1][0] - t[i][1])

    tt = 0
    work_time_list = []
    no_work_time_re = []
    total_work_time = []
    n_t = []
    check_work = []
    n_start_time = []
    n_d_list = []

    for i in range(len(t)):
        if i == 0:
            total_work_time.append(t[0][0])         #第一个时间窗的结束时间
            tt += t[0][1]
        else:                                       #出第一个时间窗外都在上一个结束时间下加上间隔时间
            tt += t[i][1] - t[i][0]

    total_work_time.append(tt)

    if len(t) > 1:                                  #如果时间窗长度大于1
        for i in range(len(t)):
            if i != 0:
                if t[i][0] - t[i - 1][1] > 0:      #如果两个时间窗之间存在时间间隔，则把时间间隔加入n_t,但是在check_work中标记为0，表示不工作，再把正常的时间窗加入n_t，表示工作
                    n_t.append([t[i - 1][1], t[i][0]])
                    n_t.append([t[i][0], t[i][1]])
                    check_work.append(0)
                    check_work.append(1)
                else:
                    n_t.append([t[i][0], t[i][1]])
                    check_work.append(1)
            else:                                #如果两个时间窗之间不存在时间间隔，把正常的时间窗加入n_t，表示工作
                n_t.append([t[i][0], t[i][1]])
                check_work.append(1)
    else:
        n_t.append([t[0][0], t[0][1]])              #加入第一个时间窗
        check_work.append(1)

    for i in range(len(start_time)):             #遍历开始时间
        no_work_time = 0                         #用来累计时间间隔中没有工作的时间
        for j in range(len(n_t)):
            if start_time[i] >= n_t[j][0] and start_time[i] <= n_t[j][1]:   #如果开始时间在n_t内部，减去没有工作的时间
                if check_work[j] == 1:
                    start_time[i] = math.floor(start_time[i] - no_work_time)    #排除可能存在的小数影响
                    n_start_time.append(start_time[i])
                    break
                else:
                    start_time[i] = math.floor(start_time[i] - no_work_time - (start_time[i] - n_t[j][0]))  #排除可能存在的小数影响
                    n_start_time.append(start_time[i])
                    break
            else:
                if check_work[j] == 0:      #如果check_work为0，则把这段时间间隔累计到no_work_time上
                    no_work_time += n_t[j][1] - n_t[j][0]

    for i in range(len(d_list)):            #遍历结束时间，与上方函数功能类似
        no_work_time = 0
        for j in range(len(n_t)):
            if d_list[i] >= n_t[j][0] and d_list[i] <= n_t[j][1]:
                if check_work[j] == 1:
                    d_list[i] = d_list[i] - no_work_time
                    d_list[i] = math.ceil(d_list[i])
                    n_d_list.append(d_list[i])
                    break
                else:
                    d_list[i] = d_list[i] - no_work_time - (d_list[i] - n_t[j][0])
                    d_list[i] = math.ceil(d_list[i])
                    n_d_list.append(d_list[i])
                    break
            else:
                if check_work[j] == 0:
                    no_work_time += n_t[j][1] - n_t[j][0]

    no_work_time_1 = 0
    for i in range(len(check_work)):        #统计不连续的时间窗
        if check_work[i] == 1:
            no_work_time_re.append(no_work_time_1)      #不连续的时间间隔
        else:
            no_work_time_1 += n_t[i][1] - n_t[i][0]   #不连续的总时间

    ttt = 0

    if len(t) > 1:                                  #把不连续的时间间隔处理为连续的
        for i in range(len(t)):
            if i != 0:
                if t[i][0] - t[i - 1][1] > 0:        #判断两个时间间隔之间是否连续，如果不连续则把不连续的部分累计，并把去掉不连续部分的时间减去
                    ttt += t[i][0] - t[i - 1][1]
                    work_time_list.append([t[i][0] - ttt, t[i][1] - ttt])
                else:                                #判断两个时间间隔之间是否连续，如果连续则直接加上连续的部分
                    work_time_list.append([t[i][0] - ttt, t[i][1] - ttt])
            else:
                work_time_list.append([t[i][0], t[i][1]])
    else:
        work_time_list.append([t[0][0], t[0][1]])

    return n_start_time, n_d_list, no_work_time_re, work_time_list,interval_time


def get_end_time(solution_x_total, solution_bool_sub_job, no_work_time_re, work_time_list):
    '''
    更新结束时间窗时间，该函数用于得到加入不工作时间后最终的时间窗结果
    :param solution_x_total: 所有子任务的开始处理时间和处理结束时间，单位为秒
    :param solution_bool_sub_job: 该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理
    :param no_work_time_re: 辅助处理的参数
    :param work_time_list: 辅助处理的参数
    :return: solution_x_total：最终所有子任务的开始处理时间和处理结束时间，单位为秒
    '''
    # 720 1020
    for i in range(len(solution_x_total)):
        for j in range(len(solution_x_total[i])):
            for k in range(len(solution_x_total[i][j])):
                for p in range(len(solution_x_total[i][j][k])):
                    if solution_bool_sub_job[i][j][k][p] == 1:          #如果通道启用

                        for n in range(len(work_time_list)):            #添加不工作时间
                            if solution_x_total[i][j][k][p][0] >= work_time_list[n][0] and solution_x_total[i][j][k][p][
                                0] < work_time_list[n][1]:
                                solution_x_total[i][j][k][p][0] += no_work_time_re[n]
                                break

                        for m in range(len(work_time_list)):
                            if solution_x_total[i][j][k][p][1] > work_time_list[m][0] and solution_x_total[i][j][k][p][
                                1] <= work_time_list[m][1]:
                                solution_x_total[i][j][k][p][1] += no_work_time_re[m]
                                break

    return solution_x_total


def get_end_zz_time(car_time_before, end_sxt, sbsj):
    '''
    该函数用于将自制的真实工作时间转换为自制的发车表时间
    :param car_time_before: 之前自制的车分配的时间
    :param end_sxt: 自制的真实作业时间
    :param sbsj: 货物是否被排入
    :return: end_sxt：处理后的时间，真实时间转变为发车表时间
    '''
    for i in range(len(sbsj)):
        for j in range(len(sbsj[i])):
            for k in range(len(sbsj[i][j])):
                for p in range(len(sbsj[i][j][k])):
                    if sbsj[i][j][k][p] == 1:
                        end_sxt[i][j][k][p][0] = car_time_before[i][j][k][0]
                        end_sxt[i][j][k][p][1] = car_time_before[i][j][k][1]

    return end_sxt


def time_sort(zz_begin_time_i, zz_end_time_i, zz_car_num_i):
    # 该函数用于对自制的发车表进行排序
    zz_begin_time_1 = []
    zz_end_time_1 = []
    zz_car_num_1 = []
    total_list = []

    for (i, j, k) in zip(zz_begin_time_i, zz_end_time_i, zz_car_num_i):
        total_sub_list = []
        total_sub_list.append(i)
        total_sub_list.append(j)
        total_sub_list.append(k)
        total_list.append(total_sub_list)

    total_list = sorted(total_list, key=lambda x: x[0])

    for m in range(len(total_list)):
        zz_begin_time_1.append(total_list[m][0])
        zz_end_time_1.append(total_list[m][1])
        zz_car_num_1.append(total_list[m][2])

    return zz_begin_time_1, zz_end_time_1, zz_car_num_1


def get_ini_zz_time_car(zz_begin_time, zz_end_time, zz_car_num):
    '''
    自制发车表排序预处理,自制的发车表时间是乱的，需要进行一个初步处理，让发车表时间从小到大排序，发车表的车辆也依次对应起来
    :param zz_begin_time: 自制发车表的开始时间
    :param zz_end_time: 自制发车表的结束时间
    :param zz_car_num: 自制发车表对应的车辆
    :return: e_zz_begin_time: 新的自制发车表的开始时间
    :return: e_zz_end_time: 新的自制发车表的结束时间
    :return: e_zz_car_num: 新的自制发车表对应的车辆
    '''
    e_zz_begin_time = []
    e_zz_end_time = []
    e_zz_car_num = []

    for i in range(len(zz_begin_time)):  # 按照厂家依次处理
        a_1, b_1, c_1 = time_sort(zz_begin_time[i], zz_end_time[i], zz_car_num[i])
        e_zz_begin_time.append(a_1)
        e_zz_end_time.append(b_1)
        e_zz_car_num.append(c_1)

    return e_zz_begin_time, e_zz_end_time, e_zz_car_num


def process_job_re(job_re):
    '''
    处理合并后的下标，即将重复的下标去掉
    :param job_re: EMS和自制合并后的下标
    :return: job_re_end: 处理完后的下标
    '''

    job_re_end = []

    for i in range(len(job_re)):
        re_sub = []
        for j in range(len(job_re[i])):
            re_sub_sub = []
            for k in range(len(job_re[i][j])):
                unique_items = set()
                car_re = []

                for item in job_re[i][j][k]:
                    item_tuple = tuple(item)
                    if item_tuple not in unique_items:
                        car_re.append(list(item_tuple))
                        unique_items.add(item_tuple)

                re_sub_sub.append(car_re)
            re_sub.append(re_sub_sub)
        job_re_end.append(re_sub)

    return job_re_end


def d_process(job_re_1, job_re_end_1, ems_car_d_num_1, ems_car_d_type_1, ems_car_d_goods_num_1, zz_car_d_num_1,
              zz_car_d_type_1, zz_car_d_goods_num_1):
    '''
    该函数用于得到客户需要的输出格式
    :param job_re_1: 合并后还未经处理的下标
    :param job_re_end_1: 合并后经过处理的下标
    :param ems_car_d_num_1: EMS装车模型货物的数据
    :param ems_car_d_type_1: EMS装车模型货物对应的类型的数据
    :param ems_car_d_goods_num_1: EMS装车模型货物内部数量的数据
    :param zz_car_d_num_1: 自制装车模型货物的数据
    :param zz_car_d_type_1: 自制装车模型货物对应的类型的数据
    :param zz_car_d_goods_num_1: 自制装车模型货物内部数量的数据
    :return: total_d_num:客户需要的输出格式，对应货物的数量, total_d_goods:客户需要的输出格式，对应货物内部的数量
    '''
    in_total_car_num = ems_car_d_num_1 + zz_car_d_num_1
    in_total_car_goods_num = ems_car_d_goods_num_1 + zz_car_d_goods_num_1
    in_total_car_type = ems_car_d_type_1 + zz_car_d_type_1

    total_d_num = []
    total_d_goods = []

    for i in range(len(job_re_end_1)):              #按照job_re_end_1的格式先填充数字0
        sub_total_d_num = []
        sub_total_d_goods = []
        for j in range(len(job_re_end_1[i])):
            sub_sub_total_d_num = []
            sub_sub_total_d_goods = []
            for k in range(len(job_re_end_1[i][j])):
                sub_sub_sub_total_d_num = []
                sub_sub_sub_total_d_goods = []
                for p in range(len(job_re_end_1[i][j][k])):
                    sub_sub_sub_total_d_num.append([0, 0])
                    sub_sub_sub_total_d_goods.append([0, 0])
                sub_sub_total_d_num.append(sub_sub_sub_total_d_goods)
                sub_sub_total_d_goods.append(sub_sub_sub_total_d_num)
            sub_total_d_num.append(sub_sub_total_d_num)
            sub_total_d_goods.append(sub_sub_total_d_goods)
        total_d_num.append(sub_total_d_num)
        total_d_goods.append(sub_total_d_goods)

    for i in range(len(job_re_1)):               #按照job_re_end_1的格式先填充货物类型和货物数量
        for j in range(len(job_re_1[i])):
            for k in range(len(job_re_1[i][j])):
                for p in range(len(job_re_1[i][j][k])):
                    if in_total_car_type[i][j][k][p] == 1:
                        total_d_num[i][j][k][job_re_end_1[i][j][k].index(job_re_1[i][j][k][p])][0] = \
                            in_total_car_num[i][j][k][p]
                        total_d_goods[i][j][k][job_re_end_1[i][j][k].index(job_re_1[i][j][k][p])][0] = \
                            in_total_car_goods_num[i][j][k][p]
                    else:
                        total_d_num[i][j][k][job_re_end_1[i][j][k].index(job_re_1[i][j][k][p])][1] = \
                            in_total_car_num[i][j][k][p]
                        total_d_goods[i][j][k][job_re_end_1[i][j][k].index(job_re_1[i][j][k][p])][1] = \
                            in_total_car_goods_num[i][j][k][p]

    return total_d_num, total_d_goods


def start_end_time_process(ems_begin_time, ems_end_time, time_windows,logger):
    '''
    EMS开始结束时间范围预处理，由于EMS给出的开始时间和deadline可能不在时间窗的范围内，因此这里做出处理，若不在范围内，就以时间窗的最早开始时间和最晚结束时间作为EMS厂家的开始时间和deadline
    :param ems_begin_time:EMS的开始时间
    :param ems_end_time:EMS的结束时间
    :param time_windows:时间窗
    :return:ems_begin_time EMS的开始时间, ems_end_time EMS的结束时间
    '''

    min_time = time_windows[0][0]       #时间窗开始时间
    max_time = time_windows[-1][-1]     #时间窗结束时间

    for i in range(len(ems_begin_time)):#如果ems开始时间早于时间窗开始时间，则把ems开始时间置为时间窗开始时间
        if ems_begin_time[i] < min_time:
            ems_begin_time[i] = min_time

    for j in range(len(ems_end_time)):#如果ems开始时间晚于时间窗结束时间，则把ems结束时间置为时间窗结束时间
        if ems_end_time[j] > max_time:
            ems_end_time[j] = max_time

    for i in range(len(ems_begin_time)):    #如果ems开始时间晚于结束时间，则判断排不进货物，提前退出
        if ems_begin_time[i] > ems_end_time[i]:
            logger.error("ems的开始时间晚于结束时间,排不进货物！程序结束")
            exit()

    return ems_begin_time, ems_end_time


def solution_c_ems_process(end_solution_x_total, ems_goods_num, ems_job_type, solution_bool_sub_job, solution_bool_C,
                          dis, floor_speed_map,ems_floor,floor_port_num_map):
    '''
    通道结果更新，该函数对资源占用过多的通道进行处理
    :param end_solution_x_total: 时间窗得到的求解时间
    :param ems_goods_num: 货物内部数量
    :param ems_job_type: 货物对应的类型
    :param solution_bool_sub_job: 排入的货物是否有效
    :param solution_bool_C: 通道占用情况
    :param dis: 打折系数
    :param floor_speed_map: 楼层速度参数
    :param ems_floor: ems楼层参数
    :param floor_port_num_map: 楼层通道参数
    :return: solution_bool_C：处理完成的通道
    '''

    # for v in range(len(v_j)):
    #     if int(v_j[v] * dis) != 0:
    #         v_j[v] = int(v_j[v] * dis)
    #     else:
    #         v_j[v] = 1
    floor_speed_map_integer = {}
    for v in floor_speed_map:
        floor_speed_map_integer[v] = int(floor_speed_map[v] * dis)#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    for i in range(len(solution_bool_sub_job)):
        for j in range(len(solution_bool_sub_job[i])):
            for k in range(len(solution_bool_sub_job[i][j])):
                for p in range(len(solution_bool_sub_job[i][j][k])):
                    if solution_bool_sub_job[i][j][k][p] == 1:
                        if sum(solution_bool_C[i][j][k][0]) > 1:
                            # for b in range(len(job_re[i][j][k])):
                            #     for q in range(len(ems_job_type[i][j][job_re[i][j][k][b][2]])):
                            if ems_job_type[i][j][k][p] == 1 and sum(
                                    solution_bool_C[i][j][k][0][0:floor_port_num_map[ems_floor[i]]]) > 1:
                                if ems_goods_num[i][j][k][p] <= (
                                        end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                        floor_speed_map_integer[ems_floor[i]] + 0.01):
                                    c_list = []
                                    for n in range(len(solution_bool_C[i][j][k][0])):
                                        if n < floor_port_num_map[ems_floor[i]]:
                                            if solution_bool_C[i][j][k][0][n] == 1:
                                                c_list.append(n)
                                    z_list = random.sample(c_list,
                                                           sum(solution_bool_C[i][j][k][0][0:floor_port_num_map[ems_floor[i]]]) - 1)
                                    for m in range(len(z_list)):
                                        solution_bool_C[i][j][k][0][z_list[m]] = 0
                                elif ems_goods_num[i][j][k][p] < (
                                        end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                        (sum(solution_bool_C[i][j][k][0][0:floor_port_num_map[ems_floor[i]]]) - 1) * floor_speed_map_integer[ems_floor[i]] + 0.01) and ems_goods_num[i][j][k][p] > (
                                        end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                        floor_speed_map_integer[ems_floor[i]] + 0.01):
                                    c_num = (ems_goods_num[i][j][k][p] / (
                                            end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][
                                        0]) - 0.01) / floor_speed_map_integer[ems_floor[i]]
                                    c_num = int(c_num) + (c_num % 1 > 0)
                                    c_list = []
                                    for n in range(len(solution_bool_C[i][j][k][0])):
                                        if n < floor_port_num_map[ems_floor[i]]:
                                            if solution_bool_C[i][j][k][0][n] == 1:
                                                c_list.append(n)
                                    z_list = random.sample(c_list,
                                                           sum(solution_bool_C[i][j][k][0][0:floor_port_num_map[ems_floor[i]]]) - c_num)
                                    for m in range(len(z_list)):
                                        solution_bool_C[i][j][k][0][z_list[m]] = 0
                            if ems_job_type[i][j][k][p] == 0 and sum(
                                    solution_bool_C[i][j][k][0][floor_port_num_map[ems_floor[i]]::]) > 1:
                                if ems_goods_num[i][j][k][p] <= (
                                        end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                        floor_speed_map_integer[ems_floor[i]] + 0.01):
                                    c_list = []
                                    for n in range(len(solution_bool_C[i][j][k][0])):
                                        if n >= floor_port_num_map[ems_floor[i]]:
                                            if solution_bool_C[i][j][k][0][n] == 1:
                                                c_list.append(n)
                                    z_list = random.sample(c_list,
                                                           sum(solution_bool_C[i][j][k][0][floor_port_num_map[ems_floor[i]]::]) - 1)
                                    for m in range(len(z_list)):
                                        solution_bool_C[i][j][k][0][z_list[m]] = 0
                                elif ems_goods_num[i][j][k][p] < (
                                        end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                        (sum(solution_bool_C[i][j][k][0][floor_port_num_map[ems_floor[i]]::]) - 1) * floor_speed_map_integer[ems_floor[i]] + 0.01) and ems_goods_num[i][j][k][p] > (
                                        end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                        floor_speed_map_integer[ems_floor[i]] + 0.01):
                                    c_num = (ems_goods_num[i][j][k][p] / (
                                            end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][
                                        0]) - 0.01) / floor_speed_map_integer[ems_floor[i]]
                                    c_num = int(c_num) + (c_num % 1 > 0)
                                    c_list = []
                                    for n in range(len(solution_bool_C[i][j][k][0])):
                                        if n >= floor_port_num_map[ems_floor[i]]:
                                            if solution_bool_C[i][j][k][0][n] == 1:
                                                c_list.append(n)
                                    z_list = random.sample(c_list,
                                                           sum(solution_bool_C[i][j][k][0][floor_port_num_map[ems_floor[i]]::]) - c_num)
                                    for m in range(len(z_list)):
                                        solution_bool_C[i][j][k][0][z_list[m]] = 0

    return solution_bool_C


def solution_c_zz_process(end_solution_x_total, ems_goods_num, ems_job_type, solution_bool_sub_job, solution_bool_C,
                          dis, floor_speed_map,zz_floor,floor_port_num_map):
    '''
    该函数对资源占用过多的通道进行处理
    :param end_solution_x_total: 时间窗得到的求解时间
    :param ems_goods_num: 货物内部数量
    :param ems_job_type: 货物对应的类型
    :param solution_bool_sub_job: 排入的货物是否有效
    :param solution_bool_C: 通道占用情况
    :param dis: 打折系数
    :param floor_speed_map: 楼层速度参数
    :param ems_floor: ems楼层参数
    :param floor_port_num_map: 楼层通道参数
    :return: solution_bool_C：处理完成的通道
    '''

    # for v in range(len(v_j)):
    #     if int(v_j[v] * dis) != 0:
    #         v_j[v] = int(v_j[v] * dis)
    #     else:
    #         v_j[v] = 1

    floor_speed_map_integer = {}
    for v in floor_speed_map:
        floor_speed_map_integer[v] = int(floor_speed_map[v] * dis)#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    for i in range(len(solution_bool_sub_job)):
        for j in range(len(solution_bool_sub_job[i])):
            for k in range(len(solution_bool_sub_job[i][j])):
                for p in range(len(solution_bool_sub_job[i][j][k])):
                    if solution_bool_sub_job[i][j][k][p] == 1:
                        # if sum(solution_bool_C[i][j][k][0]) > 1:
                        # for b in range(len(job_re[i][j][k])):
                        #     for q in range(len(ems_job_type[i][j][job_re[i][j][k][b][2]])):
                        if ems_job_type[i][j][k][p] == 1 and len(solution_bool_C[i][j][k][0]) == (
                                floor_port_num_map[zz_floor[i]] + floor_port_num_map['plt']) and sum(
                            solution_bool_C[i][j][k][0][0:floor_port_num_map[zz_floor[i]]]) > 1:
                            if ems_goods_num[i][j][k][p] <= (
                                    end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                    floor_speed_map_integer[zz_floor[i]] + 0.01):
                                c_list = []
                                for n in range(len(solution_bool_C[i][j][k][0])):
                                    if n < floor_port_num_map[zz_floor[i]]:
                                        if solution_bool_C[i][j][k][0][n] == 1:
                                            c_list.append(n)
                                z_list = random.sample(c_list, sum(solution_bool_C[i][j][k][0][0:floor_port_num_map[zz_floor[i]]]) - 1)
                                for m in range(len(z_list)):
                                    solution_bool_C[i][j][k][0][z_list[m]] = 0
                            elif ems_goods_num[i][j][k][p] < (
                                    end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                    (sum(solution_bool_C[i][j][k][0][0:floor_port_num_map[zz_floor[i]]]) - 1) *floor_speed_map_integer[zz_floor[i]] + 0.01) and \
                                    ems_goods_num[i][j][k][p] > (
                                    end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                    floor_speed_map_integer[zz_floor[i]] + 0.01):
                                c_num = (ems_goods_num[i][j][k][p] / (
                                        end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][
                                    0]) - 0.01) / floor_speed_map_integer[zz_floor[i]]
                                c_num = int(c_num) + (c_num % 1 > 0)
                                c_list = []
                                for n in range(len(solution_bool_C[i][j][k][0])):
                                    if n < floor_port_num_map[zz_floor[i]]:
                                        if solution_bool_C[i][j][k][0][n] == 1:
                                            c_list.append(n)
                                z_list = random.sample(c_list,
                                                       sum(solution_bool_C[i][j][k][0][0:floor_port_num_map[zz_floor[i]]]) - c_num)
                                for m in range(len(z_list)):
                                    solution_bool_C[i][j][k][0][z_list[m]] = 0
                        if ems_job_type[i][j][k][p] == 0 and sum(solution_bool_C[i][j][k][0][-floor_port_num_map['plt']::]) > 1:
                            if ems_goods_num[i][j][k][p] <= (
                                    end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                    floor_speed_map_integer[zz_floor[i]] + 0.01):
                                c_list = []
                                for n in range(len(solution_bool_C[i][j][k][0])):
                                    if n >= (len(solution_bool_C[i][j][k][0]) - floor_port_num_map['plt']):
                                        if solution_bool_C[i][j][k][0][n] == 1:
                                            c_list.append(n)
                                z_list = random.sample(c_list, sum(solution_bool_C[i][j][k][0][(len(
                                    solution_bool_C[i][j][k][0]) - floor_port_num_map['plt'])::]) - 1)
                                for m in range(len(z_list)):
                                    solution_bool_C[i][j][k][0][z_list[m]] = 0
                            elif ems_goods_num[i][j][k][p] < (
                                    end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * ((
                                                                                                                          sum(
                                                                                                                              solution_bool_C[
                                                                                                                                  i][
                                                                                                                                  j][
                                                                                                                                  k][
                                                                                                                                  0][
                                                                                                                              (
                                                                                                                                      len(
                                                                                                                                          solution_bool_C[
                                                                                                                                              i][
                                                                                                                                              j][
                                                                                                                                              k][
                                                                                                                                              0]) -
                                                                                                                                  floor_port_num_map['plt'])::]) - 1) *
                                                                                                                  floor_speed_map_integer[zz_floor[i]] + 0.01) and \
                                    ems_goods_num[i][j][k][p] > (
                                    end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][0]) * (
                                    floor_speed_map_integer[zz_floor[i]] + 0.01):
                                c_num = (ems_goods_num[i][j][k][p] / (
                                        end_solution_x_total[i][j][k][p][1] - end_solution_x_total[i][j][k][p][
                                    0]) - 0.01) / floor_speed_map_integer[zz_floor[i]]
                                c_num = int(c_num) + (c_num % 1 > 0)
                                c_list = []
                                for n in range(len(solution_bool_C[i][j][k][0])):
                                    if n >= (len(solution_bool_C[i][j][k][0]) - floor_port_num_map['plt']):
                                        if solution_bool_C[i][j][k][0][n] == 1:
                                            c_list.append(n)
                                z_list = random.sample(c_list, sum(solution_bool_C[i][j][k][0][(len(
                                    solution_bool_C[i][j][k][0]) - floor_port_num_map['plt'])::]) - c_num)
                                for m in range(len(z_list)):
                                    solution_bool_C[i][j][k][0][z_list[m]] = 0

    return solution_bool_C


def priority_process(ems_priority, zz_priority, ems_goods_num, ems_begin_time, ems_end_time, ems_job_type, ems_goods,
                     zz_goods_num, zz_begin_time, zz_end_time, zz_job_type, zz_goods, fu_dong_EMS, fu_dong_zz,
                     rong_liang_EMS, rong_liang_zz, zhuan_hua_EMS, zhuan_hua_zz, EMS_interval_time, zz_interval_time,
                     zz_car_num, box_flow_value,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map,time_window,is_splitting_car
                     ):
    # 按厂家优先级将所有参数重新排序
    # 不分车模式将间隔时间直接替换成0，分车模式按入参间隔时间设置
    # 把按优先级排列后的对同一交付对象自制的发车时间升序排列
    # 最后处理分配多口箱数阈值port_assignment_map，完善成从1口到n+1口的件箱阈值

    #重新获取ems和自制的优先级及其对应序号

    sorted_result_ems = sorted(enumerate(ems_priority), key=lambda x: x[1])
    sorted_result_zz = sorted(enumerate(zz_priority), key=lambda x: x[1])

    original_indices_ems = [index for index, _ in sorted_result_ems]
    original_indices_zz = [index for index, _ in sorted_result_zz]

    ems_floor = [  int(e_f[0])  for e_f in ems_floor ]
    zz_floor = [  int(z_f[0])  for z_f in zz_floor ]



    floor_speed_map_ = {}
    floor_port_num_map_ = {}
    floor_delivery_num_map_ = {}
    port_assignment_map_ = {}

    #将一些使用字符键值改为数字键值，方便后续程序处理

    for fsm in floor_speed_map:
        if fsm =='plt':
            floor_speed_map_['plt'] = floor_speed_map[fsm]
        else:
            floor_speed_map_[int(fsm)] = floor_speed_map[fsm]

    for fpnm in floor_port_num_map:
        if fpnm =='plt':
            floor_port_num_map_['plt'] = floor_port_num_map[fpnm]
        else:
            floor_port_num_map_[int(fpnm)] = floor_port_num_map[fpnm]

    for fdnm in floor_delivery_num_map:
        if fdnm =='plt':
            floor_delivery_num_map_['plt'] = floor_delivery_num_map[fdnm]
        else:
            floor_delivery_num_map_[int(fdnm)] = floor_delivery_num_map[fdnm]

    for fap in port_assignment_map:
        if fap =='plt':
            port_assignment_map_['plt'] =  [[int(item) for item in row] for row in port_assignment_map[fap]]
        else:
            port_assignment_map_[int(fap)] =  [[int(item) for item in row] for row in port_assignment_map[fap]]


    new_ems_goods_num = []
    new_ems_begin_time = []
    new_ems_end_time = []
    new_ems_job_type = []
    new_c = []
    new_ems_goods = []
    new_zz_goods_num = []
    new_zz_begin_time = []
    new_zz_end_time = []
    new_zz_job_type = []
    new_zz_goods = []
    new_fu_dong_EMS = []
    new_fu_dong_zz = []
    new_rong_liang_EMS = []
    new_rong_liang_zz = []
    new_zhuan_hua_EMS = []
    new_zhuan_hua_zz = []
    new_EMS_interval_time = []
    new_zz_interval_time = []
    new_zz_car_num = []
    new_ems_floor = []
    new_zz_floor = []

    #按照新的优先级排序
    for i in original_indices_ems:
        new_ems_goods_num.append(ems_goods_num[i])
        new_ems_begin_time.append(ems_begin_time[i])
        new_ems_end_time.append(ems_end_time[i])
        new_ems_job_type.append(ems_job_type[i])
        # new_c.append(c[i])
        new_ems_goods.append(ems_goods[i])
        new_fu_dong_EMS.append(fu_dong_EMS[i])
        new_rong_liang_EMS.append(rong_liang_EMS[i])
        new_zhuan_hua_EMS.append(zhuan_hua_EMS[i])
        if(is_splitting_car==False):
            new_EMS_interval_time.append(0)
        else:
            new_EMS_interval_time.append(EMS_interval_time[i])
        new_ems_floor.append(ems_floor[i])

    for j in original_indices_zz:
        new_zz_goods_num.append(zz_goods_num[j])
        new_zz_begin_time.append(zz_begin_time[j])
        new_zz_end_time.append(zz_end_time[j])
        new_zz_job_type.append(zz_job_type[j])
        new_zz_goods.append(zz_goods[j])
        new_zz_car_num.append(zz_car_num[j])
        new_fu_dong_zz.append(fu_dong_zz[j])
        new_rong_liang_zz.append(rong_liang_zz[j])
        new_zhuan_hua_zz.append(zhuan_hua_zz[j])
        if(is_splitting_car==False):
            new_zz_interval_time.append(0)
        else:
            new_zz_interval_time.append(zz_interval_time[j])
        new_zz_floor.append(zz_floor[j])

    for i in range(len(new_zz_begin_time)):

        indexed_A = list(enumerate(new_zz_begin_time[i]))
        sorted_indexed_A = sorted(indexed_A, key=lambda x: x[1])
        sorted_indices = [idx for idx, _ in sorted_indexed_A]

        new_zz_begin_time[i] = [new_zz_begin_time[i][idx] for idx in sorted_indices]
        new_zz_end_time[i] = [new_zz_end_time[i][idx] for idx in sorted_indices]
        new_zz_car_num[i] = [new_zz_car_num[i][idx] for idx in sorted_indices]


    #将port_assignment_map_中各楼层对应的货物数量排序，为了方便后续程序处理，增加了0个货物和99999999个货物的数据
    for port in port_assignment_map_:
        port_assignment_map_[port] = sorted(port_assignment_map_[port],key=lambda x:x[1])
        port_assignment_map_[port].insert(0,[1,0])
        port_assignment_map_[port].append([ port_assignment_map_[port][len(port_assignment_map_[port])-1][0] + 1 , 99999999])




    return new_ems_goods_num, new_ems_begin_time, new_ems_end_time, new_ems_job_type, new_ems_goods, new_zz_goods_num, \
           new_zz_begin_time, new_zz_end_time, new_zz_job_type, new_zz_goods, new_fu_dong_EMS, new_fu_dong_zz, \
           new_rong_liang_EMS, new_rong_liang_zz, new_zhuan_hua_EMS, new_zhuan_hua_zz, new_EMS_interval_time, new_zz_interval_time, \
           original_indices_ems, original_indices_zz, new_zz_car_num,new_ems_floor,new_zz_floor,floor_speed_map_,floor_port_num_map_,floor_delivery_num_map_,port_assignment_map_



def sub_remove_du_two(deliver_plan_time, detail_port_num,detail_id_arr):
    # 两个时间元素的去重

    '''
    :param deliver_plan_time
    :param detail_port_num
    :param detail_id_arr
    :return new_deliver_plan_time
    :return new_detail_port_num
    :return new_detail_id_arr
    '''

    new_deliver_plan_time = []
    new_detail_port_num = []
    new_detail_id_arr = []
    du_list = []
    unique_items = set()
    for i in range(len(deliver_plan_time)):
        # sub_du_list = deliver_plan_time[i] + detail_port_num[i]
        sub_du_list = []
        sub_du_list.append(tuple([tuple(deliver_plan_time[i][0]), tuple(deliver_plan_time[i][1])]))
        sub_du_list.append(tuple(detail_port_num[i]))
        du_list.append(sub_du_list)

    for i in range(len(deliver_plan_time)):
        item_tuple = tuple(du_list[i])
        if item_tuple not in unique_items:
            unique_items.add(item_tuple)
            new_deliver_plan_time.append([list(item_tuple[0][0]), list(item_tuple[0][1])])
            new_detail_port_num.append(list(item_tuple[1]))
            new_detail_id_arr.append(detail_id_arr[i])

    return new_deliver_plan_time, new_detail_port_num,new_detail_id_arr


def sub_remove_du_one(deliver_plan_time, detail_port_num, detail_id_arr):
    # 只有一个时间元素的去重
    new_deliver_plan_time = []
    new_detail_port_num = []
    new_detail_id_arr = []
    du_list = []
    unique_items = set()
    for i in range(len(deliver_plan_time)):
        # sub_du_list = deliver_plan_time[i] + detail_port_num[i]
        sub_du_list = []
        sub_du_list.append(tuple(deliver_plan_time[i][0]))
        sub_du_list.append(tuple(detail_port_num[i]))
        du_list.append(sub_du_list)

    for i in range(len(deliver_plan_time)):
        item_tuple = tuple(du_list[i])
        if item_tuple not in unique_items:
            unique_items.add(item_tuple)
            new_deliver_plan_time.append([list(item_tuple[0])])
            new_detail_port_num.append(list(item_tuple[1]))
            new_detail_id_arr.append(detail_id_arr[i])

    return new_deliver_plan_time, new_detail_port_num, new_detail_id_arr


def remove_du(ems_time_lock, ems_port_lock, ems_id_lock):
    # 主去重函数
    ems_time_lock_two = []
    ems_port_lock_two = []
    ems_id_lock_two = []
    ems_time_lock_one = []
    ems_port_lock_one = []
    ems_id_lock_one = []
    new_ems_time_lock_one = []
    new_ems_port_lock_one = []
    new_ems_id_lock_one = []

    for i in range(len(ems_time_lock)):
        if len(ems_time_lock[i]) == 2:
            ems_time_lock_two.append(ems_time_lock[i])
            ems_port_lock_two.append(ems_port_lock[i])
            ems_id_lock_two.append(ems_id_lock[i])

        else:
            ems_time_lock_one.append(ems_time_lock[i])
            ems_port_lock_one.append(ems_port_lock[i])
            ems_id_lock_one.append(ems_id_lock[i])

    if bool(ems_time_lock_two):
        ems_time_lock_two, ems_port_lock_two,ems_id_lock_two = sub_remove_du_two(ems_time_lock_two, ems_port_lock_two,ems_id_lock_two)

    if bool(ems_time_lock_one):
        ems_time_lock_one, ems_port_lock_one,ems_id_lock_one = sub_remove_du_one(ems_time_lock_one, ems_port_lock_one,ems_id_lock_one)

    if bool(ems_time_lock_two) and bool(ems_time_lock_one):

        index_list = []

        for i in range(len(ems_time_lock_one)):
            for j in range(len(ems_time_lock_two)):
                if ems_time_lock_one[i][0] == ems_time_lock_two[j][0][0] and ems_port_lock_one[i] == ems_port_lock_two[
                    j]:
                    index_list.append(i)

        for i in range(len(ems_time_lock_one)):
            if i not in index_list:
                new_ems_time_lock_one.append(ems_time_lock_one[i])
                new_ems_port_lock_one.append(ems_port_lock_one[i])
                new_ems_id_lock_one.append(ems_id_lock_one[i])

        end_ems_time_lock = ems_time_lock_two + new_ems_time_lock_one
        end_ems_port_lock = ems_port_lock_two + new_ems_port_lock_one
        end_ems_id_lock = ems_id_lock_two + new_ems_id_lock_one
    else:
        end_ems_time_lock = ems_time_lock_two + ems_time_lock_one
        end_ems_port_lock = ems_port_lock_two + ems_port_lock_one
        end_ems_id_lock = ems_id_lock_two + ems_id_lock_one

    return end_ems_time_lock, end_ems_port_lock, end_ems_id_lock


def zz_sub_remove_du_two(deliver_plan_time, detail_port_num, detail_id_arr):
    '''
    两个时间元素的去重
    :param deliver_plan_time    #插单货物的时间窗    维度1，维度2，维度3 =  厂家，件箱/栈板，时间
    :param detail_port_num      #插单货物的通道号    维度1，维度2 =  厂家，通道号
    :param detail_id_arr        #插单货物的序号      维度1 =  序号
    :return
     new_deliver_plan_time      #更新后的插单货物的时间窗    维度1，维度2，维度3 =  厂家，件箱/栈板，时间
     new_detail_port_num        #更新后的插单货物的通道号    维度1，维度2 =  厂家，通道号
     new_detail_id_arr          #更新后的插单货物的序号      维度1 =  序号
    '''
    new_deliver_plan_time = []
    new_detail_port_num = []
    new_detail_id_arr = []
    du_list = []
    unique_items = set()
    for i in range(len(deliver_plan_time)):           #把入参合在一起
        # sub_du_list = deliver_plan_time[i] + detail_port_num[i]
        sub_du_list = []
        sub_du_list.append(tuple([tuple(deliver_plan_time[i][0]), tuple(deliver_plan_time[i][1])]))
        sub_du_list.append(tuple(detail_port_num[i]))
        du_list.append(sub_du_list)

    for i in range(len(deliver_plan_time)):         #去重
        item_tuple = tuple(du_list[i])
        if item_tuple not in unique_items:
            unique_items.add(item_tuple)
            new_deliver_plan_time.append([list(item_tuple[0][0]), list(item_tuple[0][1])])
            new_detail_port_num.append(list(item_tuple[1]))
            new_detail_id_arr.append(detail_id_arr[i])

    return new_deliver_plan_time, new_detail_port_num, new_detail_id_arr


def zz_sub_remove_du_one(deliver_plan_time, detail_port_num, ems_port_lock_one_id):

    '''
    只有一个时间元素的去重
    :param deliver_plan_time    #插单货物的时间窗    维度1，维度2，维度3 =  厂家，件箱/栈板，时间
    :param detail_port_num      #插单货物的通道号    维度1，维度2 =  厂家，通道号
    :param detail_id_arr        #插单货物的序号      维度1 =  序号
    :return
     new_deliver_plan_time      #更新后的插单货物的时间窗    维度1，维度2，维度3 =  厂家，件箱/栈板，时间
     new_detail_port_num        #更新后的插单货物的通道号    维度1，维度2 =  厂家，通道号
     new_detail_id_arr          #更新后的插单货物的序号      维度1 =  序号
    '''

    new_deliver_plan_time = []
    new_detail_port_num = []
    new_detail_id_arr = []
    du_list = []
    unique_items = set()
    for i in range(len(deliver_plan_time)):
        # sub_du_list = deliver_plan_time[i] + detail_port_num[i]
        sub_du_list = []
        sub_du_list.append(tuple(deliver_plan_time[i][0]))
        sub_du_list.append(tuple(detail_port_num[i]))
        du_list.append(sub_du_list)

    for i in range(len(deliver_plan_time)):
        item_tuple = tuple(du_list[i])
        if item_tuple not in unique_items:
            unique_items.add(item_tuple)
            new_deliver_plan_time.append([list(item_tuple[0])])
            new_detail_port_num.append(list(item_tuple[1]))
            new_detail_id_arr.append(ems_port_lock_one_id[i])

    return new_deliver_plan_time, new_detail_port_num, new_detail_id_arr


def zz_remove_du(ems_time_lock, ems_port_lock, detail_id_arr):
    #

    '''
    主去重函数

    :param ems_time_lock    #插单货物的时间窗    维度1，维度2，维度3 =  厂家，件箱/栈板，时间
    :param ems_port_lock      #插单货物的通道号    维度1，维度2 =  厂家，通道号
    :param detail_id_arr        #插单货物的序号      维度1 =  序号

    :return
    end_ems_time_lock        #插单货物的时间窗    维度1，维度2，维度3 =  厂家，件箱/栈板，时间
    end_ems_port_lock       #插单货物的通道号    维度1，维度2 =  厂家，通道号
    end_ems_port_lock_id        #插单货物的序号      维度1 =  序号
    '''

    ems_time_lock_two = []
    ems_port_lock_two = []
    ems_port_lock_two_id = []
    ems_time_lock_one = []
    ems_port_lock_one = []
    ems_port_lock_one_id = []
    new_ems_time_lock_one = []
    new_ems_port_lock_one = []
    new_ems_port_lock_one_id = []

    for i in range(len(ems_time_lock)):
        if len(ems_time_lock[i]) == 2:                                          #如果同时存在件箱和栈板，统计
            ems_time_lock_two.append(ems_time_lock[i])
            ems_port_lock_two.append(ems_port_lock[i])
            ems_port_lock_two_id.append(detail_id_arr[i])
        else:                                                                   #只存在件箱或栈板，单独统计
            ems_time_lock_one.append(ems_time_lock[i])
            ems_port_lock_one.append(ems_port_lock[i])
            ems_port_lock_one_id.append(detail_id_arr[i])

    if bool(ems_time_lock_two):
        ems_time_lock_two, ems_port_lock_two, ems_port_lock_two_id = zz_sub_remove_du_two(ems_time_lock_two,
                                                                                          ems_port_lock_two,
                                                                                          ems_port_lock_two_id)     #两个时间元素的去重

    if bool(ems_time_lock_one):
        ems_time_lock_one, ems_port_lock_one, ems_port_lock_one_id = zz_sub_remove_du_one(ems_time_lock_one,
                                                                                          ems_port_lock_one,
                                                                                          ems_port_lock_one_id)    #只有一个时间元素的去重

    if bool(ems_time_lock_two) and bool(ems_time_lock_one):

        index_list = []

        for i in range(len(ems_time_lock_one)):         #记录重复的索引
            for j in range(len(ems_time_lock_two)):
                if ems_time_lock_one[i][0] == ems_time_lock_two[j][0][0] and ems_port_lock_one[i] == ems_port_lock_two[
                    j]:
                    index_list.append(i)

        for i in range(len(ems_time_lock_one)):         #记录不重复的索引
            if i not in index_list:
                new_ems_time_lock_one.append(ems_time_lock_one[i])
                new_ems_port_lock_one.append(ems_port_lock_one[i])
                new_ems_port_lock_one_id.append(ems_port_lock_one_id[i])
                                                        #去重后的数据
        end_ems_time_lock = ems_time_lock_two + new_ems_time_lock_one
        end_ems_port_lock = ems_port_lock_two + new_ems_port_lock_one
        end_ems_port_lock_id = ems_port_lock_two_id + new_ems_port_lock_one_id
    else:
        end_ems_time_lock = ems_time_lock_two + ems_time_lock_one
        end_ems_port_lock = ems_port_lock_two + ems_port_lock_one
        end_ems_port_lock_id = ems_port_lock_two_id + ems_port_lock_one_id

    return end_ems_time_lock, end_ems_port_lock, end_ems_port_lock_id


def remove_lock_time(deliver_plan_time, detail_port_num, detail_id_arr, insert_time, zz_begin_time, zz_end_time,
                     zz_car_num, zz_interval_time, zz_car_m, zz_car_m_type, dis,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,is_splitting_car):

    '''
    移除重复锁单时间    把重复的锁单时间删除
    :param deliver_plan_time     #插单货物的时间窗    维度1，维度2，维度3 =  厂家，件箱/栈板，时间
    :param detail_port_num       #插单货物的通道号    维度1，维度2 =  厂家，通道号
    :param detail_id_arr         #插单货物的序号      维度1 =  序号
    :param insert_time           #插入时间
    :param zz_begin_time         #自制开始时间
    :param zz_end_time           #自制结束时间
    :param zz_car_num            #车辆数量
    :param zz_interval_time      #自制时间间隔
    :param zz_car_m              #自制车辆类型
    :param zz_car_m_type         #自制车辆类型
    :param dis                   #转化比例
    :param ems_floor             #ems楼层信息
    :param zz_floor              #自制楼层信息
    :param floor_speed_map       #各楼层速度信息
    :param floor_port_num_map    #各楼层通道数量信息
    :param is_splitting_car      #是否分车
    :return
    zz_begin_time                #自制开始时间
    zz_end_time                  #自制结束时间
    zz_car_num                   #自制车辆数量
    '''
    floor_speed_map_integer = {}
    for v in floor_speed_map:
        floor_speed_map_integer[v] = round(floor_speed_map[v] * dis,4)  #求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度



    lock_zz_id = []
    lock_zz_time = []
    lock_zz_port = []

    for i in range(len(detail_id_arr)):                                                     #按照数据把自制和ems把数据分开
        if bool(detail_id_arr[i]):
            # for j in range(len(detail_id_arr[i])):
            if detail_id_arr[i][0] == 0:
                lock_zz_id.append(detail_id_arr[i][1][0])
                lock_zz_time.append(deliver_plan_time[i])
                lock_zz_port.append(detail_port_num[i])

    lock_zz_time, lock_zz_port, lock_zz_id = zz_remove_du(lock_zz_time, lock_zz_port, lock_zz_id)                       # 去重函数

    for index, iid in enumerate(lock_zz_id):
        for ti in lock_zz_time[index]:
            for i in range(len(zz_begin_time[iid])):
                if ti[0] >= zz_begin_time[iid][i] and ti[1] <= zz_end_time[iid][i]:         #被锁的车次在时间间隔内并且出去分车模式则减少一辆车
                    if is_splitting_car == True:
                        zz_car_num[iid][i] -= 1
                        break

    ems_time = []
    ems_port = []
    ems_id = []
    for i in range(len(deliver_plan_time)):                  #按照数据把自制和ems把数据分开
        if bool(detail_id_arr[i]):
            if detail_id_arr[i][1] == 0:
                ems_time.append(deliver_plan_time[i])
                ems_port.append(detail_port_num[i])
                ems_id.append(detail_id_arr[i][0][0])
    ems_time, ems_port,ems_id = zz_remove_du(ems_time, ems_port, ems_id)                #被锁的车次在时间间隔内并且出去分车模式则减少一辆车
    # ems_time1, ems_port1 = remove_du(ems_time, ems_port)
    # sub_sub_resource = []
    # sub_resource = []
    # total_resource = []
    # for i in range(len(zz_begin_time)):
    #     sub_resource = []
    #     for j in range(len(zz_begin_time[i])):
    #         sub_sub_resource = []
    #         ems_b = sum(c[0][0][0]) * v_j[1] * (zz_end_time[i][j] - zz_begin_time[i][j])
    #         p = sum(c[0][0][1]) * v_j[0] * (zz_end_time[i][j] - zz_begin_time[i][j])
    #         zz_b = v_se_j[1] * (zz_end_time[i][j] - zz_begin_time[i][j])
    #         sub_sub_resource.append(ems_b)
    #         sub_sub_resource.append(p)
    #         sub_sub_resource.append(zz_b)
    #     sub_resource.append(sub_sub_resource)
    # total_resource.append(sub_resource)

    goods_resource = []
    max_end_time = 0
    zz_e_t = {}
    zz_e_t_port = {}
    for i in range(len(lock_zz_time)):
        if len(lock_zz_time[i]) == 2:       #如果有自制和ems,取锁车最大时间和时间间隔相加
            max_end_time = max(lock_zz_time[i][0][1], lock_zz_time[i][1][1]) + zz_interval_time[lock_zz_id[i]]
        else:                               #只有自制或ems,取锁车最大时间和时间间隔相加
            max_end_time = lock_zz_time[i][0][1] + zz_interval_time[lock_zz_id[i]]

        if insert_time > max_end_time:
            max_end_time = insert_time

        if lock_zz_id[i] not in zz_e_t:     #每个序号取一个最大结束时间
            zz_e_t[lock_zz_id[i]] = max_end_time
        else:
            if zz_e_t[lock_zz_id[i]] < max_end_time:
                zz_e_t[lock_zz_id[i]] = max_end_time

    for i, t in zz_e_t.items():
        if t >= zz_end_time[i][0]:
            if len(zz_end_time[i]) > 1:
                del zz_begin_time[i][0]
                del zz_end_time[i][0]
                del zz_car_num[i][0]
        else:

            re_source = {}
            for v in floor_speed_map:
                re_source[v] = (zz_end_time[i][0] - t)*floor_speed_map[v]*floor_port_num_map[v]  # 求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

            ems_b = 0
            p = 0
            ems_bp = {}
            for v in floor_speed_map:
                ems_bp[v] = 0
            for m in range(len(ems_time)):
                if len(ems_time[m]) == 2:   #如果既有件箱也有栈板
                    if ems_time[m][0][0] < t and ems_time[m][0][1] > t and ems_time[m][0][1] < zz_end_time[i][0]:       #锁车的结束时间在ems开始时间和ems结束时间内，并且在自制结束时间内，则取锁车时间和ems结束时间的时间间隔计算资源占用
                        ems_bp[ems_floor[ems_id[m]]] += (ems_time[m][0][1] - t) * sum(ems_port[m][0:floor_port_num_map[ems_floor[ems_id[m]]]]) * floor_speed_map[ems_floor[ems_id[m]]]
                    elif ems_time[m][0][0] > t and ems_time[m][0][1] > zz_end_time[i][0] and ems_time[m][0][0] < \
                            zz_end_time[i][0]:                                                                          #锁车的结束时间在ems开始时间之前，并且在自制结束时间之后，则取自制和ems的时间间隔计算资源占用
                        ems_bp[ems_floor[ems_id[m]]] += (zz_end_time[i][0] - ems_time[m][0][0]) * sum(ems_port[m][0:floor_port_num_map[ems_floor[ems_id[m]]]]) * floor_speed_map[ems_floor[ems_id[m]]]
                    elif ems_time[m][0][0] <= t and ems_time[m][0][1] >= zz_end_time[i][0]:                             #锁车的开始时间在自制结束时间之后，则取自制结束时间和锁车结束时间的时间间隔计算资源占用
                        ems_bp[ems_floor[ems_id[m]]] += (zz_end_time[i][0] - t) * sum(ems_port[m][0:floor_port_num_map[ems_floor[ems_id[m]]]]) * floor_speed_map[ems_floor[ems_id[m]]]

                    if ems_time[m][1][0] < t and ems_time[m][1][1] > t and ems_time[m][1][1] < zz_end_time[i][0]:       #栈板计算逻辑，与上同理
                        ems_bp['plt'] += (ems_time[m][1][1] - t) * sum(ems_port[m][floor_port_num_map[ems_floor[ems_id[m]]]::]) * floor_speed_map['plt']
                    elif ems_time[m][1][0] > t and ems_time[m][1][1] > zz_end_time[i][0] and ems_time[m][1][0] < \
                            zz_end_time[i][0]:
                        ems_bp['plt'] += (zz_end_time[i][0] - ems_time[m][1][0]) * sum(ems_port[m][floor_port_num_map[ems_floor[ems_id[m]]]::]) * floor_speed_map['plt']
                    elif ems_time[m][1][0] <= t and ems_time[m][1][1] >= zz_end_time[i][0]:
                        ems_bp['plt'] += (zz_end_time[i][0] - t) * sum(ems_port[m][floor_port_num_map[ems_floor[ems_id[m]]]::]) * floor_speed_map['plt']
                else:                                                                                                   #只有件箱或者只有栈板的计算逻辑也是与上同理
                    if sum(ems_port[m][0:floor_port_num_map[ems_floor[ems_id[m]]]]) >= 1:
                        if ems_time[m][0][0] < t and ems_time[m][0][1] > t and ems_time[m][0][1] < zz_end_time[i][0]:
                            ems_bp[ems_floor[ems_id[m]]] += (ems_time[m][0][1] - t) * sum(ems_port[m][0:floor_port_num_map[ems_floor[ems_id[m]]]]) * floor_speed_map[ems_floor[ems_id[m]]]
                        elif ems_time[m][0][0] > t and ems_time[m][0][1] > zz_end_time[i][0] and ems_time[m][0][0] < \
                                zz_end_time[i][0]:
                            ems_bp[ems_floor[ems_id[m]]] += (zz_end_time[i][0] - ems_time[m][0][0]) * sum(ems_port[m][0:floor_port_num_map[ems_floor[ems_id[m]]]]) * \
                                     floor_speed_map[ems_floor[ems_id[m]]]
                        elif ems_time[m][0][0] <= t and ems_time[m][0][1] >= zz_end_time[i][0]:
                            ems_bp[ems_floor[ems_id[m]]] += (zz_end_time[i][0] - t) * sum(ems_port[m][0:floor_port_num_map[ems_floor[ems_id[m]]]]) * floor_speed_map[ems_floor[ems_id[m]]]
                    else:
                        if ems_time[m][0][0] < t and ems_time[m][0][1] > t and ems_time[m][0][1] < zz_end_time[i][0]:
                            ems_bp['plt'] += (ems_time[m][0][1] - t) * sum(ems_port[m][floor_port_num_map[ems_floor[ems_id[m]]]::]) * floor_speed_map['plt']
                        elif ems_time[m][0][0] > t and ems_time[m][0][1] > zz_end_time[i][0] and ems_time[m][0][0] < \
                                zz_end_time[i][0]:
                            ems_bp['plt'] += (zz_end_time[i][0] - ems_time[m][1][0]) * sum(ems_port[m][floor_port_num_map[ems_floor[ems_id[m]]]::]) * floor_speed_map['plt']
                        elif ems_time[m][0][0] <= t and ems_time[m][0][1] >= zz_end_time[i][0]:
                            ems_bp['plt'] += (zz_end_time[i][0] - t) * sum(ems_port[m][floor_port_num_map[ems_floor[ems_id[m]]]::]) * floor_speed_map['plt']

            car_ems_b = 0
            car_p = 0
            car_zz_b = 0
            car_bp = {}
            for v in floor_speed_map:
                car_bp[v] = 0
            # if s_c[i][0][0] == 1:
            #     for k in range(len(zz_car_m[i][0][0])):
            #         if zz_car_m_type[i][0][0][k] == 1:
            #             car_zz_b += zz_car_m[i][0][0][k]
            #         else:
            #             car_p += zz_car_m[i][0][0][k]
            # else:
            #     for k in range(len(zz_car_m[i][0][0])):
            #         if zz_car_m_type[i][0][0][k] == 1:
            #             car_ems_b += zz_car_m[i][0][0][k]
            #         else:
            #             car_p += zz_car_m[i][0][0][k]

            for k in range(len(zz_car_m[i][0][0])):
                if zz_car_m_type[i][0][0][k] == 1:
                    car_bp[zz_floor[k]] += zz_car_m[i][0][0][k]
                else:
                    car_bp['plt'] += zz_car_m[i][0][0][k]

            re_sum = 0
            for v in floor_speed_map:
                re_sum += (re_source[v] - car_bp[v] - ems_bp[v])  #累计资源占用

            if re_sum < 0:
                if len(zz_begin_time[i]) > 1:
                    del zz_begin_time[i][0]
                    del zz_end_time[i][0]
                    del zz_car_num[i][0]

    for i in range(len(zz_car_num)):
        for j in range(len(zz_car_num[i])):
            if zz_car_num[i][j] < 1:
                del zz_begin_time[i][j]
                del zz_end_time[i][j]
                del zz_car_num[i][j]
                break

    return zz_begin_time, zz_end_time, zz_car_num


def zz_process_1(job_total, job_type_total, job_re, goods_num_new, out_car, car_type, car_goods_d, car_num, begin_time,
                 end_time):
    '''
    自制删车预处理，将超过给定车辆数量的部分删除
    :param job_total    #自制任务的具体信息，即货物数量
    :param job_type_total      #货物形态 0代表栈板，1代表件箱
    :param job_re        #记录每辆车装载的货物编号
    :param goods_num_new    #每辆车装的总货物数量， 维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物数量
    :param out_car      #每辆车装的货物量(没乘转化系数)，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    :param car_type        #装车模型的货物类型，与car相对应，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物类型
    :param car_goods_d    #每辆车装的货物数量，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物数量
    :param car_num          #车辆数量
    :param begin_time       #开始时间
    :param end_time         #结束时间
    '''
    no_car_re_temp = []
    no_car_type_temp = []
    no_out_car_temp = []

    for i in range(len(job_total)):                     #厂家遍历
        if bool(car_num[i]):                            #如果存在车辆
            total_car_num = sum(car_num[i])
            car_num_check = 0
            for j in range(len(job_total[i])):          #订单遍历
                for k in range(len(job_total[i][j])):   #订单详情遍历
                    if car_num_check < total_car_num:   #如果安排的车辆总数大于所给的车辆数，则删除一部分车
                        car_num_check += 1
                    else:
                        no_car_re_temp += job_re[i][j][k:len(job_re[i][j])]
                        no_out_car_temp += out_car[i][j][k:len(out_car[i][j])]
                        no_car_type_temp += car_type[i][j][k:len(car_type[i][j])]
                        del job_total[i][j][k:len(job_total[i][j])]
                        del job_type_total[i][j][k:len(job_type_total[i][j])]
                        del job_re[i][j][k:len(job_re[i][j])]
                        del goods_num_new[i][j][k:len(goods_num_new[i][j])]
                        del out_car[i][j][k:len(out_car[i][j])]
                        del car_type[i][j][k:len(car_type[i][j])]
                        del car_goods_d[i][j][k:len(car_goods_d[i][j])]
                        break
        else:
            no_car_re_temp += job_re[i][0][:]
            no_out_car_temp += out_car[i][0][:]
            no_car_type_temp += car_type[i][0][:]

    job_total = [job_total[i] for i in range(len(car_num)) if bool(car_num[i]) is True]
    job_type_total = [job_type_total[i] for i in range(len(car_num)) if bool(car_num[i]) is True]
    job_re = [job_re[i] for i in range(len(car_num)) if bool(car_num[i]) is True]
    goods_num_new = [goods_num_new[i] for i in range(len(car_num)) if bool(car_num[i]) is True]
    out_car = [out_car[i] for i in range(len(car_num)) if bool(car_num[i]) is True]
    car_type = [car_type[i] for i in range(len(car_num)) if bool(car_num[i]) is True]
    car_goods_d = [car_goods_d[i] for i in range(len(car_num)) if bool(car_num[i]) is True]
    begin_time = [begin_time[i] for i in range(len(car_num)) if bool(car_num[i]) is True]
    end_time = [end_time[i] for i in range(len(car_num)) if bool(car_num[i]) is True]
    car_num = [car_num[i] for i in range(len(car_num)) if bool(car_num[i]) is True]



    no_car_re_temp = sum(no_car_re_temp, [])  #遍历列表并合成一维的
    no_car_type_temp = sum(no_car_type_temp, [])
    no_out_car_temp = sum(no_out_car_temp, [])

    no_job_data_re_temp = [[no_car_type_temp[i] * no_out_car_temp[i], (1 - no_car_type_temp[i]) * no_out_car_temp[i]]
                           for i in range(len(no_car_re_temp))]     #前件箱货物量，后栈板货物量

    new_no_job_data_re_temp = []
    new_no_car_re_temp = []
    re_s = set()
    for i in range(len(no_car_re_temp)):
        if tuple(no_car_re_temp[i]) not in re_s:                    #根据货物编号去重
            re_s.add(tuple(no_car_re_temp[i]))
            new_no_car_re_temp.append(copy.deepcopy(no_car_re_temp[i]))
            new_no_job_data_re_temp.append(copy.deepcopy(no_job_data_re_temp[i]))
        else:                                                        #如果货物编号已经存在，则累计货物量
            new_no_job_data_re_temp[new_no_car_re_temp.index(no_car_re_temp[i])][0] += copy.deepcopy(no_job_data_re_temp[i][0])
            new_no_job_data_re_temp[new_no_car_re_temp.index(no_car_re_temp[i])][1] += copy.deepcopy(no_job_data_re_temp[i][1])

    no_car_re = []
    no_job_data_re = []

    if new_no_car_re_temp != []:
        slow = 0
        temp = new_no_job_data_re_temp[0]                               #
        for i in range(1, len(new_no_car_re_temp)):
            if new_no_car_re_temp[i] != new_no_car_re_temp[slow]:
                no_job_data_re.append(temp)
                no_car_re.append(new_no_car_re_temp[slow])
                temp = [0, 0]
                slow = i

            temp[0] += new_no_job_data_re_temp[i][0]
            temp[1] += new_no_job_data_re_temp[i][1]
        no_job_data_re.append(temp)
        no_car_re.append(new_no_car_re_temp[slow])
    job_total, job_type_total, job_re, goods_num_new, out_car, car_type, car_goods_d, new_no_car_re_temp, no_job_data_re, begin_time, end_time, car_num = copy.deepcopy(job_total), copy.deepcopy(job_type_total), copy.deepcopy(job_re), copy.deepcopy(goods_num_new), copy.deepcopy(out_car), copy.deepcopy(car_type), copy.deepcopy(car_goods_d), copy.deepcopy(new_no_car_re_temp),copy.deepcopy(no_job_data_re), copy.deepcopy(begin_time), copy.deepcopy(end_time), copy.deepcopy(car_num)
    return job_total, job_type_total, job_re, goods_num_new, out_car, car_type, car_goods_d, new_no_car_re_temp,no_job_data_re, begin_time, end_time, car_num


def get_insert_start_time(insert_time, deliver_plan_time, detail_port_num, detail_id_arr, ems_begin_time,
                          EMS_interval_time, zz_interval_time):
    # 开始时间更新，根据插入时间更新ems开始时间、更新自制开始时间
    #     :param insert_time   对应于EMS厂家的最早开始时间，只有一个维度
    #     :param deliver_plan_time     对应于EMS厂家的最晚结束时间，只有一个维度
    #     :param detail_port_num    对应于自制厂家每辆车的最早开始时间， 维度1，维度2=  厂家，时间
    #     :param detail_id_arr      对应于自制厂家每辆车的最晚结束时间，维度1，维度2=  厂家，时间
    #     :param ems_begin_time      插入时间
    #     :param EMS_interval_time      插入时间
    #     :param EMS_interval_time      插入时间
    #     :return ems_time_lock
    #     :return ems_port_lock
    #     :return ems_id_lock
    #     :return zz_time_lock
    #     :return zz_port_lock
    #     :return zz_id_lock
    #     :return zz_d1
    #     :return ems_begin_time

    ems_time_lock = []
    ems_port_lock = []
    ems_id_lock = []
    zz_time_lock = []
    zz_port_lock = []
    zz_id_lock = []
    zz_begin_time_c = []
    zz_re = []

    for i in range(len(detail_id_arr)):
        if bool(detail_id_arr[i]):
            if detail_id_arr[i][1] == 0:
                if len(deliver_plan_time[i]) == 2:
                    max_end_time = max(deliver_plan_time[i][0][1], deliver_plan_time[i][1][1])
                    if insert_time >= deliver_plan_time[i][0][0] and insert_time < max_end_time:
                        ems_time_lock.append(deliver_plan_time[i])
                        ems_port_lock.append(detail_port_num[i])
                        ems_id_lock.append(detail_id_arr[i][0][0])
                else:
                    max_end_time = deliver_plan_time[i][0][1]
                    if insert_time >= deliver_plan_time[i][0][0] and insert_time < max_end_time:
                        ems_time_lock.append(deliver_plan_time[i])
                        ems_port_lock.append(detail_port_num[i])
                        ems_id_lock.append(detail_id_arr[i][0][0])
            else:
                if len(deliver_plan_time[i]) == 2:
                    max_end_time = max(deliver_plan_time[i][0][1], deliver_plan_time[i][1][1])
                    if insert_time >= deliver_plan_time[i][0][0] and insert_time < max_end_time:
                        zz_time_lock.append(deliver_plan_time[i])
                        zz_port_lock.append(detail_port_num[i])
                        zz_id_lock.append(detail_id_arr[i][1][0])
                else:
                    max_end_time = deliver_plan_time[i][0][1]
                    if insert_time >= deliver_plan_time[i][0][0] and insert_time < max_end_time:
                        zz_time_lock.append(deliver_plan_time[i])
                        zz_port_lock.append(detail_port_num[i])
                        zz_id_lock.append(detail_id_arr[i][1][0])

    ems_time_lock, ems_port_lock,ems_id_lock = remove_du(ems_time_lock, ems_port_lock,ems_id_lock)

    zz_time_lock, zz_port_lock, zz_id_lock = remove_du(zz_time_lock, zz_port_lock, zz_id_lock)

    for i in range(len(ems_begin_time)):
        if ems_begin_time[i] < insert_time:
            ems_begin_time[i] = insert_time

    for i in range(len(detail_id_arr)):
        if bool(detail_id_arr[i]):
            if detail_id_arr[i][1] == 0:
                if len(deliver_plan_time[i]) == 2:
                    max_end_time = max(deliver_plan_time[i][0][1], deliver_plan_time[i][1][1])
                else:
                    max_end_time = deliver_plan_time[i][0][1]
                if max_end_time + EMS_interval_time[detail_id_arr[i][0][0]] > ems_begin_time[detail_id_arr[i][0][0]]:
                    ems_begin_time[detail_id_arr[i][0][0]] = max_end_time + EMS_interval_time[detail_id_arr[i][0][0]]

    for i in range(len(detail_id_arr)):
        if bool(detail_id_arr[i]):
            if detail_id_arr[i][0] == 0:
                if len(deliver_plan_time[i]) == 2:
                    max_end_time = max(deliver_plan_time[i][0][1], deliver_plan_time[i][1][1])
                else:
                    max_end_time = deliver_plan_time[i][0][1]
                if max_end_time + zz_interval_time[detail_id_arr[i][1][0]] > insert_time:
                    zz_begin_time_c.append([insert_time, max_end_time + zz_interval_time[detail_id_arr[i][1][0]]])
                    zz_re.append(detail_id_arr[i])

    zz_d1 = {}
    set_1 = set()

    for i in range(len(zz_re)):
        if zz_re[i][1][0] not in set_1:
            set_1.add(zz_re[i][1][0])
            zz_d1[zz_re[i][1][0]] = zz_begin_time_c[i][1]
        else:
            if zz_begin_time_c[i][1] > zz_d1[zz_re[i][1][0]]:
                zz_d1[zz_re[i][1][0]] = zz_begin_time_c[i][1]

    return ems_time_lock, ems_port_lock, ems_id_lock, zz_time_lock, zz_port_lock, zz_id_lock, zz_d1, ems_begin_time


def insert_se_solve(job_data, job_type, data_end_start, V_j, c, a_c, dis, zz_car_time, V_EMS_j, t, zz_interval_time,
                    ems_c, ems_time_lock, ems_port_lock, ems_id_lock, zz_time_lock, zz_port_lock, zz_id_lock, zz_d1, index_original_zz,
                    insert_time, rong_liang_zz, zhuan_hua_zz, box_flow_value, zz_delivery_count, ems_delivery_count,zz_priority,max_time,random_index,random_ems_index,random_zz_index,floor_speed_map,portEmsLpnNum3,portEmsLpnNum2,portSelfLpnNum2,is_splitting_car,order_sequence,floor_port_num_map,ems_floor,zz_floor,port_assignment_map,logger):
    """
    该函数用于求解时间窗，输入输出参数解释如下
    :param job_data:EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
    :param d_list:EMS货物的截止日期
    :param job_type:EMS货物形态 0可代表栈板，1代表件箱，2代表gtp
    :param data_end_start:各个任务对应的开始时间
    :param sxt:所有自制子任务的开始处理时间和处理结束时间，单位为秒
    :param sbsj:该项对应某一个自制子任务是否被处理，若为1则被处理，若为0则没被处理
    :param sbc:该项对应自制子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用
    :param V_j: 不同类型货物对应通道的速度，数量/分钟，0的位置对应栈板，1的位置对应件箱，2的位置对应自制
    :param t:求解时间，若最后无解，则需调大时间
    :return: solution_x_total 所有子任务的开始处理时间和处理结束时间，单位为秒
    solution_bool_sub_job 该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理
    solution_bool_C 该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用
    solution_bool_C_N 方便EMS求解使用的通道参数
    """

    # # 对速度进行折扣处理
    # for v in range(len(V_j)):
    #     if int(V_j[v] * dis) != 0:
    #         V_j[v] = int(V_j[v] * dis)
    #     else:
    #         V_j[v] = 1
    # # 对速度进行折扣处理
    # for v in range(len(V_EMS_j)):
    #     if int(V_EMS_j[v] * dis) != 0:
    #         V_EMS_j[v] = int(V_EMS_j[v] * dis)
    #     else:
    #         V_EMS_j[v] = 1

    # 对速度进行折扣处理
    if (is_splitting_car==False):
        max_time = 999999999
    total_zz_cargo_num,total_ems_cargo_num = get_zz_cargo_num(job_data,job_type,c)
    total_cargo_num = get_cargo_num_(job_data,job_type)
    for v in range(len(V_j)):
        V_j[v] = int(V_j[v] * dis * 10000)

    # 对速度进行折扣处理
    for v in range(len(V_EMS_j)):
        V_EMS_j[v] = int(V_EMS_j[v] * dis * 10000)

    floor_speed_map_integer = {}
    for v in floor_speed_map:
        floor_speed_map_integer[v] = int(floor_speed_map[v] * dis * 10000)#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度
    min_end_time = []
    total_C_list = []
    bool_job_list = []
    bool_sub_job_list = []
    job_p_list = []
    x_intervals = []
    y_intervals = []
    solution_x_total = []
    solution_bool_sub_job = []
    solution_bool_C = []
    solution_bool_C_N = []
    de = []
    rs_c = []
    rs_zz_delivery_count = []
    rs_ems_delivery_count = []
    total_bb = 0
    total_bbb = 0

    model = cp_model.CpModel()

    for i in range(len(job_data)):  # 厂家层级遍历
        j_b = model.NewBoolVar('%d' % i)  # 该厂家的车是否全部排完
        total_bb += j_b
        bool_job_list.append(j_b)
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        bool_sub_ssub_job = []

        c_num_occupy = {}
        for port_num in floor_port_num_map:
            c_num_occupy[port_num] = [[] for _ in range(floor_port_num_map[port_num])]
        c_occupy_s = {}
        for j,port_num in enumerate(floor_port_num_map):
            c_occupy_s[port_num] = [model.NewIntVar(0, 100, 'p_e_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]
        c_occupy = {}
        for j,port_num in enumerate(floor_port_num_map) :
            c_occupy[port_num] = [model.NewBoolVar('ocp_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]


        # ems_c_num_occupy = [[] for _ in range(len(random_ems_index))]
        # zz_c_num_occupy = [[] for _ in range(len(random_zz_index))]
        # ems_c_occupy_s = [model.NewIntVar(0, 100, 'p_e_%d' % (i)) for i in range(len(random_ems_index))]
        # zz_c_occupy_s = [model.NewIntVar(0, 100, 'p_e_%d' % (i)) for i in range(len(random_zz_index))]
        # ems_c_occupy = [model.NewBoolVar('ocp_%d' % (i)) for i in range(len(random_ems_index))]
        # zz_c_occupy = [model.NewBoolVar('ocp_%d' % (i)) for i in range(len(random_zz_index))]

        for j in range(len(job_data[i])):  # 订单层级的遍历
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))  # 订单是否完成
            bool_sub_job.append(j_sub_b)
            u_bool_sub_sub_job = []
            u_job_p_sub_sub = []
            u_sub_C_list = []
            u_bool_sub_job_se = []

            for k in range(len(job_data[i][j])):  # 车辆层级遍历
                u_j_sub_b_se = model.NewBoolVar('%d_%d_%d' % (i, j, k))  # 车辆是否排入
                u_bool_sub_job_se.append(u_j_sub_b_se)
                bool_sub_sub_job = []
                job_p_sub_sub = []
                sub_C_list = []
                for p in range(len(job_data[i][j][k])):  # 车内部货物类型层级遍历（件箱、栈板）
                    j_sub_sub_b = model.NewBoolVar('%d_%d_%d_%d' % (i, j, k, p))  # 货物是否被分配通道并在交期内处理
                    bool_sub_sub_job.append(j_sub_sub_b)
                    total_bbb += j_sub_sub_b
                    sub_sub_c_list = []
                    sub_sub_p_list = []
                    if zz_car_time[i][j][k][0] < insert_time:
                        a_i = insert_time
                    else:
                        a_i = zz_car_time[i][j][k][0]
                    j_sub_p_s = model.NewIntVar(a_i, max_time,
                                                'p_s_%d_%d_%d_%d' % (i, j, k, p))  # 货物开始处理时间变量
                    j_sub_p_e = model.NewIntVar(a_i, max_time,
                                                'p_e_%d_%d_%d_%d' % (i, j, k, p))  # 货物结束处理时间变量
                    j_sub_p_e_1 = model.NewIntVar(a_i, max_time,
                                                  'p_e1_%d_%d_%d_%d' % (i, j, k, p))  # 用于车辆时间间隔的变量
                    min_end_time.append(j_sub_p_e)
                    due_data_d = model.NewBoolVar('due_data_d')  # 交期是否满足的变量
                    c_d = model.NewBoolVar('c_d')  # 是否分配通道的变量
                    model.Add(j_sub_p_e <= zz_car_time[i][j][k][1]).OnlyEnforceIf(due_data_d)  # 交期约束
                    model.Add(j_sub_p_e > zz_car_time[i][j][k][1]).OnlyEnforceIf(due_data_d.Not())  # 交期约束
                    sub_sub_p_list.append(j_sub_p_s)
                    sub_sub_p_list.append(j_sub_p_e)
                    sub_sub_p_list.append(j_sub_p_e_1)
                    job_p_sub_sub.append(sub_sub_p_list)

                    if job_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                        for v in range(floor_port_num_map['plt']):  # 遍历通道
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, 7))
                            sub_sub_c_list.append(b)
                    else:
                        for m in range(floor_port_num_map[zz_floor[i]]):
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                            sub_sub_c_list.append(b)
                            c_num_occupy[zz_floor[i]][m].append(b)

                    model.Add(sum(sub_sub_c_list) <= job_data[i][j][k][p])
                    model.Add(sum(sub_sub_c_list) > 0).OnlyEnforceIf(c_d)  # 分配通道，c_d为1
                    model.Add(sum(sub_sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
                    # model.Add(due_data_d == 1).OnlyEnforceIf(c_d)
                    model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_sub_b)  # 交期通道两个全满足，货物进去
                    model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_sub_b.Not())
                    sub_C_list.append(sub_sub_c_list)
                u_job_p_sub_sub.append(job_p_sub_sub)
                u_sub_C_list.append(sub_C_list)
                u_bool_sub_sub_job.append(bool_sub_sub_job)
                model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(
                    u_j_sub_b_se)  # 件箱和栈板全部排入或件箱、栈板排入就代表车排入了
                model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(u_j_sub_b_se.Not())

            model.Add(sum(u_bool_sub_job_se) == len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b)  # 车全排入了，就代表订单完成了
            model.Add(sum(u_bool_sub_job_se) < len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b.Not())

            C_list.append(u_sub_C_list)
            bool_sub_ssub_job.append(u_bool_sub_sub_job)
            job_p_sub.append(u_job_p_sub_sub)

        if total_cargo_num[i] >0:
            [model.Add(c_occupy_s[zz_floor[i]][v] == sum(c_num_occupy[zz_floor[i]][v])) for v in range(len(c_occupy_s[zz_floor[i]]))]
            for v in range(len(c_occupy[zz_floor[i]])):
                model.Add(c_occupy_s[zz_floor[i]][v] > 0).OnlyEnforceIf(c_occupy[zz_floor[i]][v])
                model.Add(c_occupy_s[zz_floor[i]][v] <= 0).OnlyEnforceIf(c_occupy[zz_floor[i]][v].Not())

            for port_assignment_idx in range(len(port_assignment_map[zz_floor[i]])-1):
                if total_cargo_num[i] >= port_assignment_map[zz_floor[i]][port_assignment_idx][1] and total_cargo_num[i]<= port_assignment_map[zz_floor[i]][port_assignment_idx+1][1]:
                    model.Add(sum(c_occupy[zz_floor[i]]) == port_assignment_map[zz_floor[i]][port_assignment_idx][0])

        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)  # 所有订单完成了，厂家完成了
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())

        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_ssub_job)
        job_p_list.append(job_p_sub)
    # if (is_splitting_car==False):
    #     for i in range(1,len(order_sequence)):
    #         for j in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]])):
    #             for k in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j])):
    #                 for a in range(len(job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]])):
    #                     for u in range(len(job_p_list[order_sequence[i - 1][0]][order_sequence[i - 1][1]][a])):
    #                         model.Add(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j][k][0]>=job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]][a][u][1])

    port_num_sum = {}
    sub_port_num_sum = 0
    for floor_port_num in (floor_port_num_map):
        port_num_sum[floor_port_num] = sub_port_num_sum
        sub_port_num_sum += floor_port_num_map[floor_port_num]


    # 资源占用
    # if bool(ems_time_lock):
    #     for i in range(len(ems_time_lock)):
    #         for k in range(len(ems_port_lock[i])):
    #             if k < len(ems_c[0][0][0]):
    #                 if ems_port_lock[i][k] == 1 and (int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0])) > 0:
    #                     x_s = model.NewConstant(int(ems_time_lock[i][0][0]))
    #                     ii = model.NewConstant(int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0]))
    #                     x_e = model.NewConstant(int(ems_time_lock[i][0][1]))
    #                     y_s = model.NewConstant(port_num_sum[ems_floor[i]] + k)
    #                     iii = model.NewConstant(1)
    #                     y_e = model.NewConstant(port_num_sum[ems_floor[i]] + k + 1)
    #
    #                     x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
    #                     y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
    #                     x_intervals.append(x_ii)
    #                     rs_ems_delivery_count.append(x_ii)
    #                     y_intervals.append(y_ii)
    #             else:
    #                 if ems_port_lock[i][k] == 1:
    #                     if ems_time_lock[i] == 2:
    #                         if (int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0])) > 0:
    #                             x_s = model.NewConstant(int(ems_time_lock[i][1][0]))
    #                             ii = model.NewConstant(int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0]))
    #                             x_e = model.NewConstant(int(ems_time_lock[i][1][1]))
    #                             y_s = model.NewConstant(port_num_sum['plt'])
    #                             iii = model.NewConstant(1)
    #                             y_e = model.NewConstant(port_num_sum['plt'] + 1)
    #
    #                             x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
    #                             y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
    #                             x_intervals.append(x_ii)
    #                             # rs_ems_delivery_count.append(x_ii)
    #                             y_intervals.append(y_ii)
    #                     else:
    #                         if (int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0])) > 0:
    #                             x_s = model.NewConstant(int(ems_time_lock[i][0][0]))
    #                             ii = model.NewConstant(int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0]))
    #                             x_e = model.NewConstant(int(ems_time_lock[i][0][1]))
    #                             y_s = model.NewConstant(port_num_sum['plt'])
    #                             iii = model.NewConstant(1)
    #                             y_e = model.NewConstant(port_num_sum['plt'] + 1)
    #
    #                             x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
    #                             y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
    #                             # rs_ems_delivery_count.append(x_ii)
    #                             x_intervals.append(x_ii)
    #                             y_intervals.append(y_ii)

    # if bool(zz_time_lock):
    #     for i in range(len(zz_time_lock)):
    #         if len(zz_port_lock[i]) == (1 + len(c[0][0][1])):
    #             for j in range(len(zz_port_lock[i])):
    #                 if j < 1:
    #                     if zz_port_lock[i][j] == 1 and (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
    #                         x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
    #                         ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
    #                         x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
    #                         y_s = model.NewConstant(port_num_sum[ems_floor[i]] + j)
    #                         iii = model.NewConstant(1)
    #                         y_e = model.NewConstant(port_num_sum[ems_floor[i]] + 1 + j)
    #
    #                         x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
    #                         y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
    #                         rs_zz_delivery_count.append(x_ii)
    #                         x_intervals.append(x_ii)
    #                         y_intervals.append(y_ii)
    #                 else:
    #                     if zz_port_lock[i][j] == 1:
    #                         if len(zz_time_lock[i]) == 2:
    #                             if (int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0])) > 0:
    #                                 x_s = model.NewConstant(int(zz_time_lock[i][1][0]))
    #                                 ii = model.NewConstant(int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0]))
    #                                 x_e = model.NewConstant(int(zz_time_lock[i][1][1]))
    #                                 y_s = model.NewConstant(port_num_sum['plt'])
    #                                 iii = model.NewConstant(1)
    #                                 y_e = model.NewConstant(port_num_sum['plt'] + 1)
    #
    #                                 x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
    #                                 y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
    #                                 # rs_zz_delivery_count.append(x_ii)
    #                                 x_intervals.append(x_ii)
    #                                 y_intervals.append(y_ii)
    #                         else:
    #                             if (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
    #                                 x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
    #                                 ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
    #                                 x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
    #                                 y_s = model.NewConstant(port_num_sum['plt'])
    #                                 iii = model.NewConstant(1)
    #                                 y_e = model.NewConstant(port_num_sum['plt'] + 1)
    #
    #                                 x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
    #                                 y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
    #                                 # rs_zz_delivery_count.append(x_ii)
    #                                 x_intervals.append(x_ii)
    #                                 y_intervals.append(y_ii)
    #         elif len(zz_port_lock[i]) == (len(ems_c[0][0][0]) + len(c[0][0][1])):
    #             for j in range(len(zz_port_lock[i])):
    #                 if j < len(ems_c[0][0][0]):
    #                     if zz_port_lock[i][j] == 1 and (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
    #                         x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
    #                         ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
    #                         x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
    #                         y_s = model.NewConstant(port_num_sum[zz_floor[i]]+ j)
    #                         iii = model.NewConstant(1)
    #                         y_e = model.NewConstant(port_num_sum[zz_floor[i]] + 1 + j)
    #
    #                         x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
    #                         y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
    #                         rs_zz_delivery_count.append(x_ii)
    #                         x_intervals.append(x_ii)
    #                         y_intervals.append(y_ii)
    #                 else:
    #                     if zz_port_lock[i][j] == 1:
    #                         if len(zz_time_lock[i]) == 2:
    #                             if (int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0])) > 0:
    #                                 x_s = model.NewConstant(int(zz_time_lock[i][1][0]))
    #                                 ii = model.NewConstant(int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0]))
    #                                 x_e = model.NewConstant(int(zz_time_lock[i][1][1]))
    #                                 y_s = model.NewConstant(port_num_sum['plt'])
    #                                 iii = model.NewConstant(1)
    #                                 y_e = model.NewConstant(port_num_sum['plt'] + 1)
    #
    #                                 x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
    #                                 y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
    #                                 # rs_zz_delivery_count.append(x_ii)
    #                                 x_intervals.append(x_ii)
    #                                 y_intervals.append(y_ii)
    #                         else:
    #                             if (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
    #                                 x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
    #                                 ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
    #                                 x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
    #                                 y_s = model.NewConstant(port_num_sum['plt'])
    #                                 iii = model.NewConstant(1)
    #                                 y_e = model.NewConstant(port_num_sum['plt'] + 1)
    #
    #                                 x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
    #                                 y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
    #                                 # rs_zz_delivery_count.append(x_ii)
    #                                 x_intervals.append(x_ii)
    #                                 y_intervals.append(y_ii)

    if bool(ems_time_lock):
        for i in range(len(ems_time_lock)):
            for k in range(len(ems_port_lock[i])):
                if k < len(ems_port_lock[i]) - floor_port_num_map['plt']:
                    if ems_port_lock[i][k] == 1 and (int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0])) > 0:
                        x_s = model.NewConstant(int(ems_time_lock[i][0][0]))
                        ii = model.NewConstant(int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0]))
                        x_e = model.NewConstant(int(ems_time_lock[i][0][1]))
                        y_s = model.NewConstant(port_num_sum[ems_floor[i]] + k)
                        iii = model.NewConstant(1)
                        y_e = model.NewConstant(port_num_sum[ems_floor[i]] + k + 1)

                        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                        x_intervals.append(x_ii)
                        rs_ems_delivery_count.append(x_ii)
                        y_intervals.append(y_ii)
                else:
                    if ems_port_lock[i][k] == 1:
                        if ems_time_lock[i] == 2:
                            if (int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0])) > 0:
                                x_s = model.NewConstant(int(ems_time_lock[i][1][0]))
                                ii = model.NewConstant(int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0]))
                                x_e = model.NewConstant(int(ems_time_lock[i][1][1]))
                                y_s = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                                x_intervals.append(x_ii)
                                # rs_ems_delivery_count.append(x_ii)
                                y_intervals.append(y_ii)
                        else:
                            if (int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0])) > 0:
                                x_s = model.NewConstant(int(ems_time_lock[i][0][0]))
                                ii = model.NewConstant(int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0]))
                                x_e = model.NewConstant(int(ems_time_lock[i][0][1]))
                                y_s = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                                # rs_ems_delivery_count.append(x_ii)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)

    if bool(zz_time_lock):
        for i in range(len(zz_time_lock)):
            for j in range(len(zz_port_lock[i])):
                if j < len(zz_port_lock[i]) - floor_port_num_map['plt']:
                    if zz_port_lock[i][j] == 1 and (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
                        x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
                        ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
                        x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
                        y_s = model.NewConstant(port_num_sum[zz_floor[i]] + j)
                        iii = model.NewConstant(1)
                        y_e = model.NewConstant(port_num_sum[zz_floor[i]] + 1 + j)

                        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
                        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
                        rs_zz_delivery_count.append(x_ii)
                        x_intervals.append(x_ii)
                        y_intervals.append(y_ii)
                else:
                    if zz_port_lock[i][j] == 1:
                        if len(zz_time_lock[i]) == 2:
                            if (int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0])) > 0:
                                x_s = model.NewConstant(int(zz_time_lock[i][1][0]))
                                ii = model.NewConstant(int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0]))
                                x_e = model.NewConstant(int(zz_time_lock[i][1][1]))
                                y_s = model.NewConstant(
                                    port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(
                                    port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)
                        else:
                            if (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
                                x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
                                ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
                                x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
                                y_s = model.NewConstant(
                                    port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(
                                    port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)

    # 接下来分配通达，并计算运输时间
    for i in range(len(job_data)):  # 厂家层级遍历
        for j in range(len(job_data[i])):  # 订单层级遍历
            x_tt_intervals = []
            zz_i_index = index_original_zz[i]
            if zz_i_index in zz_d1:
                x_i_s = model.NewConstant(int(insert_time))
                zz_ii = model.NewConstant(int(zz_d1[zz_i_index]) - int(insert_time))
                x_i_e = model.NewConstant(int(zz_d1[zz_i_index]))
                xi_ii = model.NewOptionalIntervalVar(x_i_s, zz_ii, x_i_e, 1, 'x_ziizii%d' % i)
                x_tt_intervals.append(xi_ii)
            for e in range(len(job_data[i][j])):  # 车辆遍历
                ini = []
                cd = []
                mm_v = model.NewIntVar(0, max_time, 'p_e_%d_%d' % (i, j))
                for p in range(len(job_data[i][j][e])):  # 货物类型遍历
                    total_interval = 0  # 速度总和的变量
                    if job_type[i][j][e][p] == 1:  # 和EMS共享通道
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] *  floor_speed_map_integer[zz_floor[i]]
                    else:
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer['plt']
                    t_i = model.NewIntVar(1, 99999999, 't_i_%d' % j)
                    model.Add(t_i == total_interval + 1)  # 速度计算待处理
                    I = model.NewIntVar(0, 99999999, 'In_%d' % j)
                    model.AddDivisionEquality(I, job_data[i][j][e][p] * 10000, t_i)
                    ini.append(job_p_list[i][j][e][p][0])
                    cd.append(I)

                    kk = 0
                    if job_type[i][j][e][p] == 1:  # 件箱货物形态
                        # if c[i][j][0][0] == 1:  # 去负一楼
                        #     for u in range(len(c[i][j][0])):
                        #         if c[i][j][0][u] == 1:  # 通道可用，构建矩形
                        #             y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, u))
                        #             j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                        #                                                              job_p_list[i][j][e][p][1],
                        #                                                              total_C_list[i][j][e][p][u // 2],
                        #                                                              'p_%d_%d_%d_%d' % (
                        #                                                              i, j, p, u // 2))
                        #
                        #             j_sub_c_intervals = model.NewOptionalIntervalVar(a_c + u, 1, y_end,
                        #                                                              total_C_list[i][j][e][p][u // 2],
                        #                                                              'c_%d_%d_%d_%d' % (
                        #                                                              i, j, p, u // 2))
                        #             kk += 1
                        #             rs_c.append(j_sub_p_intervals)
                        #             rs_zz_delivery_count.append(j_sub_p_intervals)
                        #             de.append(int(V_j[2]))
                        #             x_intervals.append(j_sub_p_intervals)
                        #             y_intervals.append(j_sub_c_intervals)
                        # else:  # 和EMS共享
                        #     # ccc = [1, 1, 1, 1, 1, 1, 1]  # 需修改，待处理
                        #     ccc = ems_c[0][0][0]
                        #     for u in range(len(ccc)):
                        #         if ccc[u] == 1:  # 通道可用，构建矩形
                        #             y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, u))
                        #             j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                        #                                                              job_p_list[i][j][e][p][1],
                        #                                                              total_C_list[i][j][e][p][u],
                        #                                                              'p_%d_%d_%d_%d' % (i, j, p, u))
                        #
                        #             j_sub_c_intervals = model.NewOptionalIntervalVar(a_c + u + 1, 1, y_end,
                        #                                                              total_C_list[i][j][e][p][u],
                        #                                                              'c_%d_%d_%d_%d' % (i, j, p, u))
                        #             kk += 1
                        #             rs_c.append(j_sub_p_intervals)
                        #             rs_ems_delivery_count.append(j_sub_p_intervals)
                        #             de.append(int(V_j[1]))
                        #             x_intervals.append(j_sub_p_intervals)
                        #             y_intervals.append(j_sub_c_intervals)
                        for u in range(floor_port_num_map[zz_floor[i]]):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, u))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][u],
                                                                             'p_%d_%d_%d_%d' % (
                                                                                 i, j, p, u))
                            j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum[zz_floor[i]] + u, 1, y_end,
                                                                             total_C_list[i][j][e][p][u],
                                                                             'c_%d_%d_%d_%d' % (
                                                                                 i, j, p, u))

                            kk += 1
                            rs_c.append(j_sub_p_intervals)  # 最大容量约束
                            rs_zz_delivery_count.append(j_sub_p_intervals)  # 最大自制通道约束
                            de.append(int( floor_speed_map_integer[zz_floor[i]]))
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)

                    else:  # 栈板货物形态
                        # for u in range(len(c[i][j][1])):
                        #     if c[i][j][1][u] == 1:  # 口可用，构建矩形
                        #         y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                        #         j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                        #                                                          job_p_list[i][j][e][p][1],
                        #                                                          total_C_list[i][j][e][p][kk],
                        #                                                          'p_%d_%d_%d_%d' % (i, j, p, kk))
                        #
                        #         j_sub_c_intervals = model.NewOptionalIntervalVar(u, 1, y_end,
                        #                                                          total_C_list[i][j][e][p][kk],
                        #                                                          'c_%d_%d_%d_%d' % (i, j, p, kk))
                        #         kk += 1
                        #         x_intervals.append(j_sub_p_intervals)
                        #         y_intervals.append(j_sub_c_intervals)

                        for u in range(floor_port_num_map['plt']):

                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'p_%d_%d_%d_%d' % (i, j, p, kk))

                            j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum['plt'], 1, y_end,
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'c_%d_%d_%d_%d' % (i, j, p, kk))
                            kk += 1
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)


                if len(ini) == 2:  # 若一辆车有两种类型的货物
                    model.Add(ini[0] == ini[1])  # 限制开始处理时间相同
                    model.Add(bool_sub_job_list[i][j][e][0] == bool_sub_job_list[i][j][e][1])
                    I_v = model.NewIntVar(0, 99999999, 'p_e_%d_%d' % (i, j))
                    model.AddMaxEquality(I_v, cd)
                    j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], I_v + int(zz_interval_time[i]) + 1, mm_v,
                                                                       bool_sub_job_list[i][j][e][0],
                                                                       '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    x_tt_intervals.append(j_sub_p_I_intervals)
                else:
                    j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], cd[0] + int(zz_interval_time[i]) + 1,
                                                                       mm_v,
                                                                       bool_sub_job_list[i][j][e][0],
                                                                       '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    x_tt_intervals.append(j_sub_p_I_intervals)

            model.AddNoOverlap(x_tt_intervals)

    load_rate = []

    for i in range(len(job_data)):
        sub_load_rate = []
        for j in range(len(job_data[i])):
            for k in range(len(job_data[i][j])):
                total_goods = 0
                for p in range(len(job_data[i][j][k])):
                    if job_type[i][j][k][p] == 0:
                        total_goods += job_data[i][j][k][p] * zhuan_hua_zz[i]
                    else:
                        total_goods += job_data[i][j][k][p]
                sub_load_rate.append(total_goods / rong_liang_zz[i])
        load_rate.append(sub_load_rate)

    load_rate_index = []

    for i in range(len(load_rate)):
        sub_load_rate = sorted(enumerate(load_rate[i]), key=lambda x: x[1], reverse=True)
        sub_load_index = [ind for ind, _ in sub_load_rate]
        load_rate_index.append(sub_load_index)

    for i in range(len(load_rate_index)):
        if len(load_rate_index[i]) > 1:
            for k in range(len(load_rate_index[i]) - 1):
                model.Add(
                    job_p_list[i][0][load_rate_index[i][k]][0][0] < job_p_list[i][0][load_rate_index[i][k + 1]][0][0])



    priority_index = sorted(zz_priority)
    car_first_start_time = []
    for i in range(len(job_p_list)):
        sub_car_first_start_time = []
        for j in range(len(job_p_list[i])):
            for k in range(len(job_p_list[i][j])):
                sub_car_first_start_time.append(job_p_list[i][j][k][0][0])
        car_first_start_time.append(sub_car_first_start_time)

    left = 0
    for i in range(1, len(car_first_start_time)):
        if (priority_index[i] > priority_index[i - 1]):
            for j in range(left, i):
                first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % i)
                next_first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % (i + 1))
                model.AddMinEquality(first_start_time, car_first_start_time[j])
                model.AddMinEquality(next_first_start_time, car_first_start_time[i])
                model.Add(first_start_time <= next_first_start_time)
            left = i


    # for i in range(len(job_p_list)):
    #     for j in range(len(job_p_list[i])):
    #         if len(job_p_list[i][j]) > 1:
    #             for k in range(len(job_p_list[i][j]) - 1):
    #                 model.Add(job_p_list[i][j][k][0][0] < job_p_list[i][j][k + 1][0][0])
    de_zz_delivery_count = [1] * len(rs_zz_delivery_count)
    de_ems_delivery_count = [1] * len(rs_ems_delivery_count)
    model.AddNoOverlap2D(x_intervals, y_intervals)
    model.AddCumulative(rs_c, de, int(10000 * box_flow_value * dis))  # 件箱库流量约束
    model.AddCumulative(rs_zz_delivery_count, de_zz_delivery_count, zz_delivery_count)
    model.AddCumulative(rs_ems_delivery_count, de_ems_delivery_count, ems_delivery_count)


    model.Maximize(total_bbb)  # 最大化排进去的车
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = t
    status1 = solver.Solve(model)



    # 得到最终的解
    solution_find = False

    if status1 == cp_model.OPTIMAL or status1 == cp_model.FEASIBLE:
        model.Add(total_bbb == round(solver.ObjectiveValue()))
        model.Minimize(sum(min_end_time))
        status2 = solver.Solve(model)
        if status2 == cp_model.OPTIMAL or status2 == cp_model.FEASIBLE:
            solution_find = True
            if status1 == cp_model.OPTIMAL and status2 == cp_model.OPTIMAL:
                logger.info("自制时间窗模型求得最优解")
            elif (status1 == cp_model.FEASIBLE or status1 == cp_model.OPTIMAL) and (status2 == cp_model.FEASIBLE or status2 == cp_model.OPTIMAL):
                logger.info("自制时间窗模型求得次优解")
            else:
                logger.info("自制时间窗模型无解,程序结束")
                # exit()
    if solution_find == False:
        logger.error("自制时间窗模型无解,程序结束")
        # exit()

    # model.Maximize(total_bbb)  # 最大化排进去的车
    # solver = cp_model.CpSolver()
    # solver.parameters.num_search_workers = 8
    # solver.parameters.max_time_in_seconds = t
    # status = solver.Solve(model)
    #
    # # 得到最终的解
    # solution_find = False
    # if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
    #     solution_find = True
    #     if status == cp_model.OPTIMAL:
    #         logger.info("自制时间窗模型求得最优解")
    #     if status == cp_model.FEASIBLE:
    #         logger.info("自制时间窗模型求得次优解")
    # if solution_find == False:
    #     logger.error("自制时间窗模型无解")


    for i in range(len(job_data)):
        solu_x_sub = []
        for j in range(len(job_data[i])):
            u_solu_x_sub = []
            for g in range(len(job_data[i][j])):
                so = []
                for k in range(len(job_data[i][j][g])):
                    solution_x = []
                    if not solution_find:
                        solution_x.append(0)
                        solution_x.append(0)
                    else:
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][0]))
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][1]))
                    so.append(solution_x)
                u_solu_x_sub.append(so)
            solu_x_sub.append(u_solu_x_sub)
        solution_x_total.append(solu_x_sub)

    for i in range(len(job_data)):
        solu_bool_sub = []
        for j in range(len(job_data[i])):
            u_solu_bool_sub = []
            for g in range(len(job_data[i][j])):
                so = []
                for k in range(len(job_data[i][j][g])):
                    if not solution_find:
                        so.append(0)
                    else:
                        so.append(solver.Value(bool_sub_job_list[i][j][g][k]))
                u_solu_bool_sub.append(so)
            solu_bool_sub.append(u_solu_bool_sub)
        solution_bool_sub_job.append(solu_bool_sub)

    for i in range(len(job_data)):
        solu_C_sub = []
        for j in range(len(job_data[i])):
            solu_C_sub_sub = []
            for e in range(len(job_data[i][j])):
                u_solu_C_sub_sub = []
                if len(job_data[i][j][e]) == 2:
                    so = []
                    c_index_list = []
                    for p in range(len(job_data[i][j][e])):
                        # so = []
                        if job_type[i][j][e][p] == 1:
                            c_index_list.append(p)

                        # if job_type[i][j][e][p] == 0:
                        #     c_index_list.append(p)

                    for p in range(len(job_data[i][j][e])):
                        # so = []
                        # if job_type[i][j][e][p] == 1:
                        #     c_index_list.append(p)

                        if job_type[i][j][e][p] == 0:
                            c_index_list.append(p)

                    for w in range(len(total_C_list[i][j][e][c_index_list[0]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[0]][w]))
                    so = copy.deepcopy([so[random_index[zz_floor[i]][k]] for k in range(len(random_index[zz_floor[i]]))])
                    for w in range(len(total_C_list[i][j][e][c_index_list[1]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[1]][w]))
                    u_solu_C_sub_sub.append(so)
                    #

                else:
                    so = []
                    if job_type[i][j][e][0] == 1:  # 如果是件箱
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))
                        so = copy.deepcopy([so[random_index[zz_floor[i]][k]] for k in range(len(random_index[zz_floor[i]]))])
                        so = so + [0] * floor_port_num_map['plt']
                        u_solu_C_sub_sub.append(so)
                    else:  # 如果是栈板
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))
                        so = [0] * floor_port_num_map[zz_floor[i]] + so
                        u_solu_C_sub_sub.append(so)
                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C.append(solu_C_sub)

    for i in range(len(job_data)):
        solu_C_sub = []
        for j in range(len(job_data[i])):
            solu_C_sub_sub = []
            for e in range(len(job_data[i][j])):
                u_solu_C_sub_sub = []
                for p in range(len(job_data[i][j][e])):
                    so = []
                    k = 0
                    if job_type[i][j][e][p] == 1:
                        for w in range(len(total_C_list[i][j][e][p])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][p][w]))

                    else:
                        for z in range(floor_port_num_map['plt']):
                            if not solution_find:#无解则用0填充最后解
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][p][k]))
                            k += 1
                    u_solu_C_sub_sub.append(so)
                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C_N.append(solu_C_sub)

    return solution_x_total, solution_bool_sub_job, solution_bool_C, solution_bool_C_N


def insert_solve(job_data, d_list, job_type, data_end_start, sxt, sbsj, sbc, s_job_type, V_j, s_c,c, p_num, a_c, dis, t,
                 ems_interval_time, ems_time_lock, ems_port_lock, ems_id_lock, zz_time_lock, zz_port_lock, zz_id_lock, rong_liang_EMS,
                 zhuan_hua_EMS, box_flow_value, zz_delivery_count, ems_delivery_count,ems_priority,max_time,work_time_list, interval_time,random_index,random_ems_index,random_zz_index,portEmsLpnNum3,portEmsLpnNum2,portSelfLpnNum2,is_splitting_car,order_sequence,floor_port_num_map,ems_floor,zz_floor,port_assignment_map,floor_speed_map,logger):
    """
    该函数用于求解时间窗，输入输出参数解释如下
    :param job_data:EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
    :param d_list:EMS货物的截止日期
    :param job_type:EMS货物形态 0可代表栈板，1代表件箱，2代表gtp
    :param data_end_start:各个任务对应的开始时间
    :param sxt:所有自制子任务的开始处理时间和处理结束时间，单位为秒
    :param sbsj:该项对应某一个自制子任务是否被处理，若为1则被处理，若为0则没被处理
    :param sbc:该项对应自制子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用
    :param s_job_type: 自制的货物形态，0可代表栈板，1代表件箱
    :param V_j: 不同类型货物对应通道的速度，数量/分钟，0的位置对应栈板，1的位置对应件箱，2的位置对应自制
    :param c: 可用的通道
    :param p_num: 所有件箱的通道
    :param a_c: 所有栈板的通道
    :param t:求解时间，若最后无解，则需调大时间
    :return: solution_x_total 所有子任务的开始处理时间和处理结束时间，单位为秒
    solution_bool_sub_job 该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理
    solution_bool_C 该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用
    """
    # # 对速度进行折扣处理
    # for v in range(len(V_j)):
    #     if int(V_j[v] * dis) != 0:
    #         V_j[v] = int(V_j[v] * dis)
    #     else:
    #         V_j[v] = 1
    if (is_splitting_car==False):
        max_time = 999999999
    total_ems_cargo_num = get_ems_cargo_num(job_data, job_type)
    total_cargo_num = get_cargo_num_(job_data, job_type)

    # 对速度进行折扣处理
    for v in range(len(V_j)):
        V_j[v] = int(V_j[v] * dis * 10000)

    floor_speed_map_integer = {}
    for v in floor_speed_map:
        floor_speed_map_integer[v] = int(floor_speed_map[v] * dis * 10000)#求解器只能求解整形，先取整，乘大数是为了增加后续速度计算的精度

    total_C_list = []
    bool_job_list = []
    bool_sub_job_list = []
    job_p_list = []
    x_intervals = []
    y_intervals = []
    solution_x_total = []
    solution_bool_sub_job = []
    solution_bool_C = []
    de = []
    rs_c = []
    rs_zz_delivery_count = []
    rs_ems_delivery_count = []
    total_bb = 0
    total_bbb = 0
    min_end_time = []
    model = cp_model.CpModel()


    for i in range(len(job_data)):  # 厂家层级遍历
        ts = data_end_start[i]
        j_b = model.NewBoolVar('%d' % i)  # 该厂家的车是否全部排完
        total_bb += j_b
        bool_job_list.append(j_b)
        job_p_sub = []
        C_list = []
        bool_sub_job = []
        bool_sub_ssub_job = []

        c_num_occupy = {}
        for port_num in floor_port_num_map:
            c_num_occupy[port_num] = [[] for _ in range(floor_port_num_map[port_num])]
        c_occupy_s = {}
        for j,port_num in enumerate(floor_port_num_map):
            c_occupy_s[port_num] = [model.NewIntVar(0, 100, 'p_e_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]
        c_occupy = {}
        for j,port_num in enumerate(floor_port_num_map) :
            c_occupy[port_num] = [model.NewBoolVar('ocp_%d%d' % (j,k)) for k in range(floor_port_num_map[port_num])]

        # ems_c_num_occupy = [[] for _ in range(len(random_ems_index))]
        # ems_c_occupy_s = [model.NewIntVar(0, 100, 'p_e_%d' % (i)) for i in range(len(random_ems_index))]
        # ems_c_occupy = [model.NewBoolVar('ocp_%d' % (i)) for i in range(len(random_ems_index))]

        for j in range(len(job_data[i])):  # 订单层级的遍历
            j_sub_b = model.NewBoolVar('%d_%d' % (i, j))  # 订单是否完成
            bool_sub_job.append(j_sub_b)
            u_bool_sub_sub_job = []
            u_job_p_sub_sub = []
            u_sub_C_list = []
            u_bool_sub_job_se = []


            for k in range(len(job_data[i][j])):  # 车辆层级遍历
                u_j_sub_b_se = model.NewBoolVar('%d_%d_%d' % (i, j, k))
                u_bool_sub_job_se.append(u_j_sub_b_se)

                bool_sub_sub_job = []
                job_p_sub_sub = []
                sub_C_list = []
                for p in range(len(job_data[i][j][k])):  # 车内部货物类型层级遍历（件箱、栈板）
                    j_sub_sub_b = model.NewBoolVar('%d_%d_%d_%d' % (i, j, k, p))  # 货物是否被分配通道并在交期内处理
                    bool_sub_sub_job.append(j_sub_sub_b)
                    total_bbb += j_sub_sub_b
                    sub_sub_c_list = []
                    sub_sub_p_list = []
                    j_sub_p_s = model.NewIntVar(int(ts), max_time, 'p_s_%d_%d_%d_%d' % (i, j, k, p))  # 货物开始处理时间变量
                    j_sub_p_e = model.NewIntVar(int(ts), max_time, 'p_e_%d_%d_%d_%d' % (i, j, k, p))  # 货物结束处理时间变量
                    j_sub_p_e_1 = model.NewIntVar(int(ts), max_time, 'p_e1_%d_%d_%d_%d' % (i, j, k, p))  # 用于车辆时间间隔的变量
                    due_data_d = model.NewBoolVar('due_data_d')  # 交期是否满足的变量
                    min_end_time.append(j_sub_p_e)
                    c_d = model.NewBoolVar('c_d')  # 是否分配通道的变量
                    model.Add(j_sub_p_e <= d_list[i]).OnlyEnforceIf(due_data_d)  # 交期约束
                    model.Add(j_sub_p_e > d_list[i]).OnlyEnforceIf(due_data_d.Not())  # 交期约束
                    sub_sub_p_list.append(j_sub_p_s)
                    sub_sub_p_list.append(j_sub_p_e)
                    sub_sub_p_list.append(j_sub_p_e_1)
                    job_p_sub_sub.append(sub_sub_p_list)
                    # if job_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                    #     for v in range(len(c[i][j][1])):  # 遍历通道
                    #         if c[i][j][1][v] == 1:  # 通道可以使用，为0则是被禁用
                    #             b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, 7))
                    #             sub_sub_c_list.append(b)
                    # else:
                    #     for m in range(len(c[i][j][0])):
                    #         if c[i][j][0][m] == 1:
                    #             b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                    #             sub_sub_c_list.append(b)
                    #             ems_c_num_occupy[m].append(b)

                    if job_type[i][j][k][p] == 0:  # 根据货物类型来查询通道
                        for v in range(floor_port_num_map['plt']):  # 遍历通道
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, 7))
                            sub_sub_c_list.append(b)
                    else:
                        for m in range(floor_port_num_map[ems_floor[i]]):
                            b = model.NewBoolVar('%d_%d_%d_%d_%d' % (i, j, k, p, m))
                            sub_sub_c_list.append(b)
                            c_num_occupy[ems_floor[i]][m].append(b)

                    model.Add(sum(sub_sub_c_list) <= job_data[i][j][k][p])
                    model.Add(sum(sub_sub_c_list) > 0).OnlyEnforceIf(c_d)  # 分配通道，c_d为1
                    model.Add(sum(sub_sub_c_list) == 0).OnlyEnforceIf(c_d.Not())
                    # model.Add(due_data_d == 1).OnlyEnforceIf(c_d)
                    model.Add(c_d + due_data_d == 2).OnlyEnforceIf(j_sub_sub_b)  # 交期通道两个全满足，货物进去
                    model.Add(c_d + due_data_d < 2).OnlyEnforceIf(j_sub_sub_b.Not())
                    sub_C_list.append(sub_sub_c_list)
                u_job_p_sub_sub.append(job_p_sub_sub)
                u_sub_C_list.append(sub_C_list)
                u_bool_sub_sub_job.append(bool_sub_sub_job)
                model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(
                    u_j_sub_b_se)  # 件箱和栈板全部排入或件箱、栈板排入就代表车排入了
                model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(u_j_sub_b_se.Not())

            model.Add(sum(u_bool_sub_job_se) == len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b)  # 车全排入了，就代表订单完成了
            model.Add(sum(u_bool_sub_job_se) < len(u_bool_sub_job_se)).OnlyEnforceIf(j_sub_b.Not())

            C_list.append(u_sub_C_list)
            bool_sub_ssub_job.append(u_bool_sub_sub_job)
            job_p_sub.append(u_job_p_sub_sub)
            # model.Add(sum(bool_sub_sub_job) == len(bool_sub_sub_job)).OnlyEnforceIf(j_sub_b)
            # model.Add(sum(bool_sub_sub_job) < len(bool_sub_sub_job)).OnlyEnforceIf(j_sub_b.Not())

        # if total_ems_cargo_num[i] >0:
        #     [model.Add(ems_c_occupy_s[v] == sum(ems_c_num_occupy[v])) for v in range(len(ems_c_occupy_s))]
        #     for v in range(len(ems_c_occupy)):
        #         model.Add(ems_c_occupy_s[v] > 0).OnlyEnforceIf(ems_c_occupy[v])
        #         model.Add(ems_c_occupy_s[v] <= 0).OnlyEnforceIf(ems_c_occupy[v].Not())
        #     if total_ems_cargo_num[i] <= portEmsLpnNum2:
        #         model.Add(sum(ems_c_occupy) <= 1)
        #     if total_ems_cargo_num[i] > portEmsLpnNum2 and total_ems_cargo_num[i] <= portEmsLpnNum3:
        #         model.Add(sum(ems_c_occupy) <= 2)
        #     if total_ems_cargo_num[i] >= portEmsLpnNum3:
        #         model.Add(sum(ems_c_occupy) <= 3)

        if total_cargo_num[i] >0:
            [model.Add(c_occupy_s[ems_floor[i]][v] == sum(c_num_occupy[ems_floor[i]][v])) for v in range(len(c_occupy_s[ems_floor[i]]))]
            for v in range(len(c_occupy[ems_floor[i]])):
                model.Add(c_occupy_s[ems_floor[i]][v] > 0).OnlyEnforceIf(c_occupy[ems_floor[i]][v])
                model.Add(c_occupy_s[ems_floor[i]][v] <= 0).OnlyEnforceIf(c_occupy[ems_floor[i]][v].Not())

            for port_assignment_idx in range(len(port_assignment_map[ems_floor[i]])-1):
                if total_cargo_num[i] >= port_assignment_map[ems_floor[i]][port_assignment_idx][1] and total_cargo_num[i]<= port_assignment_map[ems_floor[i]][port_assignment_idx+1][1]:
                    model.Add(sum(c_occupy[ems_floor[i]]) <= port_assignment_map[ems_floor[i]][port_assignment_idx][0])

        model.Add(sum(bool_sub_job) == len(bool_sub_job)).OnlyEnforceIf(j_b)  # 所有订单完成了，厂家完成了
        model.Add(sum(bool_sub_job) < len(bool_sub_job)).OnlyEnforceIf(j_b.Not())

        total_C_list.append(C_list)
        bool_sub_job_list.append(bool_sub_ssub_job)
        job_p_list.append(job_p_sub)
    # if (is_splitting_car==False):
    #     for i in range(1,len(order_sequence)):
    #         for j in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]])):
    #             for k in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j])):
    #                 for a in range(len(job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]])):
    #                     for u in range(len(job_p_list[order_sequence[i - 1][0]][order_sequence[i - 1][1]][a])):
    #                         model.Add(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j][k][0]>=job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]][a][u][1])


    port_num_sum = {}
    sub_port_num_sum = 0
    for floor_port_num in (floor_port_num_map):
        port_num_sum[floor_port_num] = sub_port_num_sum
        sub_port_num_sum += floor_port_num_map[floor_port_num]


    # 资源占用
    # if bool(ems_time_lock):
    #     for i in range(len(ems_time_lock)):
    #         for k in range(len(ems_port_lock[i])):
    #             if k < len(c[0][0][0]):
    #                 if ems_port_lock[i][k] == 1 and (int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0])) > 0:
    #                     x_s = model.NewConstant(int(ems_time_lock[i][0][0]))
    #                     ii = model.NewConstant(int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0]))
    #                     x_e = model.NewConstant(int(ems_time_lock[i][0][1]))
    #                     y_s = model.NewConstant(a_c + 1 + k)
    #                     iii = model.NewConstant(1)
    #                     y_e = model.NewConstant(a_c + 1 + 1 + k)
    #
    #                     x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
    #                     y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
    #                     rs_ems_delivery_count.append(x_ii)
    #                     x_intervals.append(x_ii)
    #                     y_intervals.append(y_ii)
    #
    #             else:
    #                 if ems_port_lock[i][k] == 1:
    #                     if len(ems_time_lock[i]) == 2:
    #                         if (int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0])) > 0:
    #                             x_s = model.NewConstant(int(ems_time_lock[i][1][0]))
    #                             ii = model.NewConstant(int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0]))
    #                             x_e = model.NewConstant(int(ems_time_lock[i][1][1]))
    #                             y_s = model.NewConstant(k - len(c[0][0][0]))
    #                             iii = model.NewConstant(1)
    #                             y_e = model.NewConstant(k - len(c[0][0][0]) + 1)
    #
    #                             # rs_ems_delivery_count.append(x_ii)
    #                             x_intervals.append(x_ii)
    #                             y_intervals.append(y_ii)
    #
    # # for i in range(1,len(order_sequence)):
    # #     for j in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]])):
    # #         for k in range(len(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j])):
    # #             for a in range(len(job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]])):
    # #                 for u in range(len(job_p_list[order_sequence[i - 1][0]][order_sequence[i - 1][1]][a])):
    # #                     model.Add(job_p_list[order_sequence[i][0]][order_sequence[i][1]][j][k][0]>=job_p_list[order_sequence[i-1][0]][order_sequence[i-1][1]][a][u][1])
    #
    #
    # if bool(zz_time_lock):
    #     for i in range(len(zz_time_lock)):
    #         if len(zz_port_lock[i]) == (len(c[0][0][0]) + len(c[0][0][1])):
    #             for j in range(len(zz_port_lock[i])):
    #                 if j < len(c[0][0][0]):
    #                     if zz_port_lock[i][j] == 1 and (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
    #                         x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
    #                         ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
    #                         x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
    #                         y_s = model.NewConstant(a_c + 1 + j)
    #                         iii = model.NewConstant(1)
    #                         y_e = model.NewConstant(a_c + 1 + 1 + j)
    #
    #                         x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
    #                         y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
    #                         rs_zz_delivery_count.append(x_ii)
    #                         x_intervals.append(x_ii)
    #                         y_intervals.append(y_ii)
    #                 else:
    #                     if zz_port_lock[i][j] == 1:
    #                         if len(zz_time_lock[i]) == 2:
    #                             if (int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0])) > 0:
    #                                 x_s = model.NewConstant(int(zz_time_lock[i][1][0]))
    #                                 ii = model.NewConstant(int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0]))
    #                                 x_e = model.NewConstant(int(zz_time_lock[i][1][1]))
    #                                 y_s = model.NewConstant(j - len(c[0][0][0]))
    #                                 iii = model.NewConstant(1)
    #                                 y_e = model.NewConstant(j - len(c[0][0][0]) + 1)
    #
    #                                 x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
    #                                 y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
    #                                 # rs_zz_delivery_count.append(x_ii)
    #                                 x_intervals.append(x_ii)
    #                                 y_intervals.append(y_ii)
    #                         else:
    #                             if (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
    #                                 x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
    #                                 ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
    #                                 x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
    #                                 y_s = model.NewConstant(j - len(c[0][0][0]))
    #                                 iii = model.NewConstant(1)
    #                                 y_e = model.NewConstant(j - len(c[0][0][0]) + 1)
    #
    #                                 x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
    #                                 y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
    #                                 # rs_zz_delivery_count.append(x_ii)
    #                                 x_intervals.append(x_ii)
    #                                 y_intervals.append(y_ii)

    if bool(ems_time_lock):
        for i in range(len(ems_time_lock)):
            for k in range(len(ems_port_lock[i])):
                if k < len( ems_port_lock[i])- floor_port_num_map['plt']:
                    if ems_port_lock[i][k] == 1 and (int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0])) > 0:
                        x_s = model.NewConstant(int(ems_time_lock[i][0][0]))
                        ii = model.NewConstant(int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0]))
                        x_e = model.NewConstant(int(ems_time_lock[i][0][1]))
                        y_s = model.NewConstant(port_num_sum[ems_floor[i]] + k)
                        iii = model.NewConstant(1)
                        y_e = model.NewConstant(port_num_sum[ems_floor[i]] + k + 1)

                        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                        x_intervals.append(x_ii)
                        rs_ems_delivery_count.append(x_ii)
                        y_intervals.append(y_ii)
                else:
                    if ems_port_lock[i][k] == 1:
                        if ems_time_lock[i] == 2:
                            if (int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0])) > 0:
                                x_s = model.NewConstant(int(ems_time_lock[i][1][0]))
                                ii = model.NewConstant(int(ems_time_lock[i][1][1]) - int(ems_time_lock[i][1][0]))
                                x_e = model.NewConstant(int(ems_time_lock[i][1][1]))
                                y_s = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                                x_intervals.append(x_ii)
                                # rs_ems_delivery_count.append(x_ii)
                                y_intervals.append(y_ii)
                        else:
                            if (int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0])) > 0:
                                x_s = model.NewConstant(int(ems_time_lock[i][0][0]))
                                ii = model.NewConstant(int(ems_time_lock[i][0][1]) - int(ems_time_lock[i][0][0]))
                                x_e = model.NewConstant(int(ems_time_lock[i][0][1]))
                                y_s = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(port_num_sum['plt'] + k - floor_port_num_map[ems_floor[ems_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_ii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_ii%d' % i)
                                # rs_ems_delivery_count.append(x_ii)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)

    if bool(zz_time_lock):
        for i in range(len(zz_time_lock)):
            for j in range(len(zz_port_lock[i])):
                if j < len( zz_port_lock[i])- floor_port_num_map['plt']:
                    if zz_port_lock[i][j] == 1 and (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
                        x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
                        ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
                        x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
                        y_s = model.NewConstant(port_num_sum[zz_floor[i]] + j)
                        iii = model.NewConstant(1)
                        y_e = model.NewConstant(port_num_sum[zz_floor[i]] + 1 + j)

                        x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
                        y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
                        rs_zz_delivery_count.append(x_ii)
                        x_intervals.append(x_ii)
                        y_intervals.append(y_ii)
                else:
                    if zz_port_lock[i][j] == 1:
                        if len(zz_time_lock[i]) == 2:
                            if (int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0])) > 0:
                                x_s = model.NewConstant(int(zz_time_lock[i][1][0]))
                                ii = model.NewConstant(int(zz_time_lock[i][1][1]) - int(zz_time_lock[i][1][0]))
                                x_e = model.NewConstant(int(zz_time_lock[i][1][1]))
                                y_s = model.NewConstant(port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)
                        else:
                            if (int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0])) > 0:
                                x_s = model.NewConstant(int(zz_time_lock[i][0][0]))
                                ii = model.NewConstant(int(zz_time_lock[i][0][1]) - int(zz_time_lock[i][0][0]))
                                x_e = model.NewConstant(int(zz_time_lock[i][0][1]))
                                y_s = model.NewConstant(port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(port_num_sum['plt'] + j - floor_port_num_map[zz_floor[zz_id_lock[i]]] + 1)

                                x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, 1, 'x_zzii%d' % i)
                                y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, 1, 'y_zzii%d' % i)
                                x_intervals.append(x_ii)
                                y_intervals.append(y_ii)

    # 之前自制的求解，在此处作为常数矩形
    for g in range(len(sxt)):
        for i in range(len(sxt[g])):
            for k in range(len(sxt[g][i])):
                for p in range(len(sxt[g][i][k])):
                    if s_job_type[g][i][k][p] == 1:# 如果是件箱
                        for l in range(len(sbc[g][i][k][p])):
                            if sbc[g][i][k][p][l]:  # 如果通道启用
                                x_s = model.NewConstant(sxt[g][i][k][p][0])
                                ii = model.NewConstant(sxt[g][i][k][p][1] - sxt[g][i][k][p][0])
                                x_e = model.NewConstant(sxt[g][i][k][p][1])
                                y_s = model.NewConstant(l + port_num_sum[zz_floor[g]])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(l + 1 + port_num_sum[zz_floor[g]])

                                if sbsj[g][i][k][p] == 1:
                                    x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, sbsj[g][i][k][p],
                                                                        'x_ii%d' % i)
                                    y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, sbsj[g][i][k][p],
                                                                        'y_ii%d' % i)
                                    x_intervals.append(x_ii)
                                    y_intervals.append(y_ii)
                                    de.append(floor_speed_map_integer[zz_floor[g]])
                                    rs_c.append(x_ii)
                                    rs_ems_delivery_count.append(x_ii)
                    else:
                        for l in range(len(sbc[g][i][k][p])):
                            if sbc[g][i][k][p][l]:
                                x_s = model.NewConstant(sxt[g][i][k][p][0])
                                ii = model.NewConstant(sxt[g][i][k][p][1] - sxt[g][i][k][p][0])
                                x_e = model.NewConstant(sxt[g][i][k][p][1])
                                y_s = model.NewConstant(l+ port_num_sum['plt'])
                                iii = model.NewConstant(1)
                                y_e = model.NewConstant(l + 1 + port_num_sum['plt'])
                                if sbsj[g][i][k][p] == 1:
                                    x_ii = model.NewOptionalIntervalVar(x_s, ii, x_e, sbsj[g][i][k][p], 'x_ii%d' % i)
                                    y_ii = model.NewOptionalIntervalVar(y_s, iii, y_e, sbsj[g][i][k][p], 'y_ii%d' % i)
                                    x_intervals.append(x_ii)
                                    y_intervals.append(y_ii)

    # 接下来分配通达，并计算运输时间
    for i in range(len(job_data)):  # 厂家层级遍历
        for j in range(len(job_data[i])):  # 订单层级遍历
            x_tt_intervals = []
            for e in range(len(job_data[i][j])):  # 车辆遍历
                ini = []
                cd = []
                mm_v = model.NewIntVar(0, max_time, 'p_e_%d_%d_%d' % (i, j,e))
                itv2 = model.NewIntVar(-999999999, 999999999, 'itv2_%d_%d_%d' % (i, j, e))
                itv3 = model.NewIntVar(0, 999999999, 'itv3_%d_%d_%d' % (i, j, e))
                itv4 = model.NewIntVar(0, 999999999, 'itv4_%d_%d_%d' % (i, j, e))
                ems_itv = model.NewIntVar(0, 999999999, 'ems_itv_%d_%d_%d' % (i, j, e))
                for p in range(len(job_data[i][j][e])):  # 货物类型遍历
                    total_interval = 0  # 速度总和的变量
                    if job_type[i][j][e][p] == 1:  # 和EMS共享通道
                        for k in range(len(total_C_list[i][j][e][p])):
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer[ems_floor[i]]
                    else:
                        for k in range(len(total_C_list[i][j][e][p])):  # 去负一楼
                            total_interval += total_C_list[i][j][e][p][k] * floor_speed_map_integer['plt']
                    t_i = model.NewIntVar(1, 99999999, 't_i_%d' % j)
                    model.Add(t_i == total_interval + 1)  # 速度计算，待处理
                    I = model.NewIntVar(0, 99999999, 'In_%d' % j)
                    model.AddDivisionEquality(I, job_data[i][j][e][p] * 10000, t_i)
                    ini.append(job_p_list[i][j][e][p][0])
                    cd.append(I)

                    kk = 0
                    if job_type[i][j][e][p] == 1:  # 件箱货物形态
                        for u in range(floor_port_num_map[ems_floor[i]]):
                            y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                            j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                             job_p_list[i][j][e][p][1],
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'p_%d_%d_%d_%d' % (i, j, p, kk))
                            j_sub_c_intervals = model.NewOptionalIntervalVar(u+port_num_sum[ems_floor[i]], 1, y_end,
                                                                             total_C_list[i][j][e][p][kk],
                                                                             'c_%d_%d_%d_%d' % (i, j, p, kk))
                            kk += 1
                            rs_c.append(j_sub_p_intervals)
                            rs_ems_delivery_count.append(j_sub_p_intervals)
                            de.append(int(floor_speed_map_integer[ems_floor[i]]))
                            x_intervals.append(j_sub_p_intervals)
                            y_intervals.append(j_sub_c_intervals)

                    else:
                        for u in range(floor_port_num_map['plt']):
                                y_end = model.NewIntVar(1, 999, 'y_end_%d%d%d' % (i, j, kk))
                                j_sub_p_intervals = model.NewOptionalIntervalVar(job_p_list[i][j][e][p][0], I + 1,
                                                                                 job_p_list[i][j][e][p][1],
                                                                                 total_C_list[i][j][e][p][kk],
                                                                                 'p_%d_%d_%d_%d' % (i, j, p, kk))
                                j_sub_c_intervals = model.NewOptionalIntervalVar(port_num_sum['plt'] + u, 1, y_end,
                                                                                 total_C_list[i][j][e][p][kk],
                                                                                 'c_%d_%d_%d_%d' % (i, j, p, kk))
                                kk += 1
                                x_intervals.append(j_sub_p_intervals)
                                y_intervals.append(j_sub_c_intervals)

                if len(ini) == 2:  # 若一辆车有两种类型的货物
                    model.Add(ini[0] == ini[1])  # 限制开始处理时间相同
                    model.Add(bool_sub_job_list[i][j][e][0] == bool_sub_job_list[i][j][e][1])
                    I_v = model.NewIntVar(0, 99999999, 'p_e_%d_%d' % (i, j))
                    model.AddMaxEquality(I_v, cd)

                    if len(interval_time) > 0:
                        real_time_bool_var = 0
                        for kt in range(len(interval_time)):
                            it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                            rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                            rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                            model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)
                            model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                            model.Add(mm_v >= work_time_list[kt + 1][0]).OnlyEnforceIf(rag12)
                            model.Add(mm_v < work_time_list[kt + 1][0]).OnlyEnforceIf(rag12.Not())
                            model.Add(ini[0] + I_v < work_time_list[kt][1]).OnlyEnforceIf(rag13)
                            model.Add(ini[0] + I_v >= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                            model.AddMultiplicationEquality(it_bool_val, [rag11, rag12])
                            model.AddMultiplicationEquality(it_bool_val2, [it_bool_val, rag13])
                            real_time_bool_var += it_bool_val2 * interval_time[kt]

                        model.Add(itv2 == int(ems_interval_time[i]) - real_time_bool_var)
                        model.AddMaxEquality(itv3, (0, itv2))
                        model.Add(itv4 >= itv3)
                        model.Add(itv4 <= int(ems_interval_time[i]))
                        model.Add(ems_itv == I_v + itv4 + 1)
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], ems_itv,
                                                                           mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                           I_v + int(ems_interval_time[i]) + 1,
                                                                           mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量

                    x_tt_intervals.append(j_sub_p_I_intervals)
                else:
                    if len(interval_time) > 0:
                        real_time_bool_var = 0
                        for kt in range(len(interval_time)):
                            it_bool_val = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            it_bool_val2 = model.NewBoolVar('ibv_%d_%d%d%d' % (i, j, e, kt))
                            rag11 = model.NewBoolVar('rag11_%d_%d%d%d' % (i, j, e, kt))
                            rag12 = model.NewBoolVar('rag12_%d_%d%d%d' % (i, j, e, kt))
                            rag13 = model.NewBoolVar('rag13_%d_%d%d%d' % (i, j, e, kt))
                            model.Add(ini[0] < work_time_list[kt][1]).OnlyEnforceIf(rag11)
                            model.Add(ini[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag11.Not())
                            model.Add(mm_v >= work_time_list[kt][1]).OnlyEnforceIf(rag12)
                            model.Add(mm_v < work_time_list[kt][1]).OnlyEnforceIf(rag12.Not())
                            model.Add(ini[0] +cd[0] < work_time_list[kt][1]).OnlyEnforceIf(rag13)
                            model.Add(ini[0] +cd[0] >= work_time_list[kt][1]).OnlyEnforceIf(rag13.Not())
                            model.AddMultiplicationEquality(it_bool_val, [rag11, rag12])
                            model.AddMultiplicationEquality(it_bool_val2, [it_bool_val, rag13])
                            real_time_bool_var += it_bool_val2 * interval_time[kt]

                        model.Add(itv2 == int(ems_interval_time[i]) - real_time_bool_var)
                        model.AddMaxEquality(itv3, (0, itv2))
                        model.Add(itv4 >= itv3)
                        model.Add(itv4 <= int(ems_interval_time[i]))
                        model.Add(ems_itv == cd[0] + itv4 + 1)
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0], ems_itv,
                                                                           mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    else:
                        j_sub_p_I_intervals = model.NewOptionalIntervalVar(ini[0],
                                                                           cd[0] + int(ems_interval_time[i]) + 1,
                                                                           mm_v,
                                                                           bool_sub_job_list[i][j][e][0],
                                                                           '%d_%d_I' % (i, j))  # 发车间隔时间变量
                    x_tt_intervals.append(j_sub_p_I_intervals)
            model.AddNoOverlap(x_tt_intervals)
    load_rate = []

    for i in range(len(job_data)):
        sub_load_rate = []
        for j in range(len(job_data[i])):
            for k in range(len(job_data[i][j])):
                total_goods = 0
                for p in range(len(job_data[i][j][k])):
                    if job_type[i][j][k][p] == 0:
                        total_goods += job_data[i][j][k][p] * zhuan_hua_EMS[i]
                    else:
                        total_goods += job_data[i][j][k][p]
                sub_load_rate.append(total_goods / rong_liang_EMS[i])
        load_rate.append(sub_load_rate)

    load_rate_index = []

    for i in range(len(load_rate)):
        sub_load_rate = sorted(enumerate(load_rate[i]), key=lambda x: x[1], reverse=True)
        sub_load_index = [ind for ind, _ in sub_load_rate]
        load_rate_index.append(sub_load_index)

    for i in range(len(load_rate_index)):
        if len(load_rate_index[i]) > 1:
            for k in range(len(load_rate_index[i]) - 1):
                model.Add(
                    job_p_list[i][0][load_rate_index[i][k]][0][0] < job_p_list[i][0][load_rate_index[i][k + 1]][0][0])

    # for i in range(len(job_p_list)):
    #     for j in range(len(job_p_list[i])):
    #         if len(job_p_list[i][j]) > 1:
    #             for k in range(len(job_p_list[i][j]) - 1):
    #                 model.Add(job_p_list[i][j][k][0][0] < job_p_list[i][j][k + 1][0][0])



    de_zz_delivery_count = [1] * len(rs_zz_delivery_count)
    de_ems_delivery_count = [1] * len(rs_ems_delivery_count)
    model.AddNoOverlap2D(x_intervals, y_intervals)
    model.AddCumulative(rs_c, de, int(10000 * box_flow_value * dis))  # 件箱库流量约束
    model.AddCumulative(rs_zz_delivery_count, de_zz_delivery_count, zz_delivery_count)  # 件箱库流量约束
    model.AddCumulative(rs_ems_delivery_count, de_ems_delivery_count, ems_delivery_count)  # 件箱库流量约束
    # # 优先级逻辑，待处理
    # for i in range(len(job_data) - 1):
    #     model.Add(bool_job_list[i] == 1).OnlyEnforceIf(bool_job_list[i + 1])

    # 优先级逻辑
    # car_first_start_time = []
    #
    # for i in range(len(job_p_list)):
    #     sub_car_first_start_time = []
    #     for j in range(len(job_p_list[i])):
    #         for k in range(len(job_p_list[i][j])):
    #             sub_car_first_start_time.append(job_p_list[i][j][k][0][0])
    #     car_first_start_time.append(sub_car_first_start_time)
    #
    # for i in range(len(car_first_start_time) - 1):
    #     first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % i)
    #     next_first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % (i + 1))
    #     model.AddMinEquality(first_start_time, car_first_start_time[i])
    #     model.AddMinEquality(next_first_start_time, car_first_start_time[i + 1])
    #     model.Add(first_start_time <= next_first_start_time)

    priority_index = sorted(ems_priority)
    car_first_start_time = []
    for i in range(len(job_p_list)):
        sub_car_first_start_time = []
        for j in range(len(job_p_list[i])):
            for k in range(len(job_p_list[i][j])):
                sub_car_first_start_time.append(job_p_list[i][j][k][0][0])
        car_first_start_time.append(sub_car_first_start_time)

    left = 0
    for i in range(1, len(car_first_start_time)):
        if (priority_index[i] > priority_index[i - 1]):
            for j in range(left, i):
                first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % i)
                next_first_start_time = model.NewIntVar(0, 99999999, 'first_start_time_%d' % (i + 1))
                model.AddMinEquality(first_start_time, car_first_start_time[j])
                model.AddMinEquality(next_first_start_time, car_first_start_time[i])
                model.Add(first_start_time <= next_first_start_time)
            left = i

    # [model.Add(ems_c_occupy_s[i]==sum(ems_c_num_occupy[i])) for i in range(len(ems_c_occupy_s))]
    #
    # for i in range(len(ems_c_occupy)):
    #     model.Add(ems_c_occupy_s[i]>0).OnlyEnforceIf(ems_c_occupy[i])
    #     model.Add(ems_c_occupy_s[i]<=0).OnlyEnforceIf(ems_c_occupy[i].Not())
    #
    # if total_ems_cargo_num<=10 :
    #     model.Add(sum(ems_c_occupy)<=1)
    # if total_ems_cargo_num>10 and total_ems_cargo_num<=50 :
    #     model.Add(sum(ems_c_occupy)<=2)
    # if total_ems_cargo_num>=50 :
    #     model.Add(sum(ems_c_occupy)<=3)


    model.Maximize(total_bbb)  # 最大化排进去的车
    solver = cp_model.CpSolver()
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = t
    status1 = solver.Solve(model)



    # 得到最终的解
    solution_find = False

    if status1 == cp_model.OPTIMAL or status1 == cp_model.FEASIBLE:
        model.Add(total_bbb == round(solver.ObjectiveValue()))
        model.Minimize(sum(min_end_time))
        status2 = solver.Solve(model)
        if status2 == cp_model.OPTIMAL or status2 == cp_model.FEASIBLE:
            solution_find = True
            if status1 == cp_model.OPTIMAL and status2 == cp_model.OPTIMAL:
                logger.info("EMS时间窗模型求得最优解")
            elif (status1 == cp_model.FEASIBLE or status1 == cp_model.OPTIMAL) and (status2 == cp_model.FEASIBLE or status2 == cp_model.OPTIMAL):
                logger.info("EMS时间窗模型求得次优解")
            else:
                logger.info("EMS时间窗模型无解,程序结束")
                # exit()
    if solution_find == False:
        logger.error("EMS时间窗模型无解,程序结束")
        # exit()

    for i in range(len(job_data)):
        solu_x_sub = []
        for j in range(len(job_data[i])):
            u_solu_x_sub = []
            for g in range(len(job_data[i][j])):
                so = []
                for k in range(len(job_data[i][j][g])):
                    solution_x = []
                    if not solution_find:
                        solution_x.append(0)
                        solution_x.append(0)
                    else:
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][0]))
                        solution_x.append(solver.Value(job_p_list[i][j][g][k][1]))
                    so.append(solution_x)
                u_solu_x_sub.append(so)
            solu_x_sub.append(u_solu_x_sub)
        solution_x_total.append(solu_x_sub)

    for i in range(len(job_data)):
        solu_bool_sub = []
        for j in range(len(job_data[i])):
            u_solu_bool_sub = []
            for g in range(len(job_data[i][j])):
                so = []
                for k in range(len(job_data[i][j][g])):
                    if not solution_find:
                        so.append(0)
                    else:
                        so.append(solver.Value(bool_sub_job_list[i][j][g][k]))
                u_solu_bool_sub.append(so)
            solu_bool_sub.append(u_solu_bool_sub)
        solution_bool_sub_job.append(solu_bool_sub)

    for i in range(len(job_data)):
        solu_C_sub = []
        for j in range(len(job_data[i])):
            solu_C_sub_sub = []
            for e in range(len(job_data[i][j])):
                u_solu_C_sub_sub = []
                if len(job_data[i][j][e]) == 2:
                    so = []
                    c_index_list = []
                    for p in range(len(job_data[i][j][e])):
                        if job_type[i][j][e][p] == 1:
                            c_index_list.append(p)

                    for p in range(len(job_data[i][j][e])):
                        if job_type[i][j][e][p] == 0:
                            c_index_list.append(p)

                    for w in range(len(total_C_list[i][j][e][c_index_list[0]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[0]][w]))
                    for w in range(len(total_C_list[i][j][e][c_index_list[1]])):
                        if not solution_find:
                            so.append(0)
                        else:
                            so.append(solver.Value(total_C_list[i][j][e][c_index_list[1]][w]))
                    u_solu_C_sub_sub.append(so)

                else:
                    so = []
                    if job_type[i][j][e][0] == 1:
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))

                        so = so + [0] * floor_port_num_map['plt']
                        u_solu_C_sub_sub.append(so)
                    else:
                        for w in range(len(total_C_list[i][j][e][0])):
                            if not solution_find:
                                so.append(0)
                            else:
                                so.append(solver.Value(total_C_list[i][j][e][0][w]))
                        so = [0] * floor_port_num_map[ems_floor[i]] + so
                        u_solu_C_sub_sub.append(so)

                solu_C_sub_sub.append(u_solu_C_sub_sub)
            solu_C_sub.append(solu_C_sub_sub)
        solution_bool_C.append(solu_C_sub)

    return solution_x_total, solution_bool_sub_job, solution_bool_C

def get_new_detail_id_arr(detail_id_arr,index_original_ems,index_original_zz):

    '''
    重排车辆id更新,按照优先级顺序，把detail_id_arr中的id顺序重新调整一下
    :param detail_id_arr        插单中的用于表示交付对象序号的是ems还是自制的入参
    :param index_original_ems   ems序号索引
    :param index_original_zz    自制序号索引
    :return detail_id_arr    更新后的detail_id_arr
    '''

    for id in detail_id_arr:
        if id:
            if id[0] == 0:
                id[1][0] = copy.deepcopy(index_original_zz.index(id[1][0]))
            if id[1] == 0:
                id[0][0] = copy.deepcopy(index_original_ems.index(id[0][0]))
    return detail_id_arr

class Logger(object):
    """
    Mock Interface
    Logger
    """

    @staticmethod
    def info(msg):
        print(f'[INFO] {Logger.date_str(datetime.now())} {msg}')

    @staticmethod
    def error(msg):
        print(f'[ERROR] {Logger.date_str(datetime.now())} {msg}')

    @staticmethod
    def date_str(date: datetime):
        return date.strftime('%Y-%m-%d %H:%M:%S') if date else None


def interval_Intersection(time_window, global_time,logger):
    '''
    时间窗和工厂日历可用时间处理
    :param time_window: 时间窗
    :param global_time: 工厂日历
    :return time_window: 时间窗
    '''
    if global_time == []:
        logger.error("人员设备工作类型的工厂日历时间段为空!程序结束")
        exit()

    global_time.sort(key=lambda x: (x[0]))  #

    newt = []
    i = 0
    j = 0
    while (i < len(time_window) and j < len(global_time)):
        if (time_window[i][1] < global_time[j][0]):
            i = i + 1
            continue
        if (time_window[i][0] > global_time[j][1]):
            j = j + 1
            continue
        newt.append([max(time_window[i][0], global_time[j][0]), min(time_window[i][1], global_time[j][1])])
        if (time_window[i][1] > global_time[j][1]):
            j = j + 1
        else:
            i = i + 1
    if (newt == []):
        logger.error("时间窗和工厂日历没有重合的工作时间!程序结束")
        exit()
    return newt


def time_process(ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time,insert_time,zz_car_num,logger=Logger):
    '''
    直接使用时间戳时间可能超过求解器的允许的最大数值，因此需要对所有设计时间的参数进行归一化
    根据插入时间更新ems开始时间、更新自制开始时间
    :param ems_begin_time   对应于EMS厂家的最早开始时间，只有一个维度
    :param ems_end_time     对应于EMS厂家的最晚结束时间，只有一个维度
    :param zz_begin_time    对应于自制厂家每辆车的最早开始时间， 维度1，维度2=  厂家，时间
    :param zz_end_time      对应于自制厂家每辆车的最晚结束时间，维度1，维度2=  厂家，时间
    :param time_window      时间窗
    :param  global_time     工厂日历
    :param insert_time      插入时间
    :param zz_car_num       自制车的数量
    :return ems_begin_time   对应于EMS厂家的最早开始时间，只有一个维度
    :return ems_end_time     对应于EMS厂家的最晚结束时间，只有一个维度
    :return zz_begin_time    对应于自制厂家每辆车的最早开始时间， 维度1，维度2=  厂家，时间
    :return zz_end_time      对应于自制厂家每辆车的最晚结束时间，维度1，维度2=  厂家，时间
    :return time_window      时间窗
    :return  global_time     工厂日历
    :return insert_time      插入时间
    :return zz_car_num       自制车的数量
    '''


    min_ems_begin_time = min(ems_begin_time) if ems_begin_time != [] else max_value
    min_ems_end_time = min(ems_end_time) if ems_end_time != [] else max_value
    min_zz_begin_time = min(min(zz_begin_time)) if zz_begin_time != [] else max_value
    min_zz_end_time = min(min(zz_end_time)) if zz_end_time != [] else max_value
    min_time_window = min(min(time_window)) if time_window != [] else max_value
    min_global_time = min(min(global_time)) if global_time != [] else max_value
    min_time = min(min_ems_begin_time,min_ems_end_time,min_zz_begin_time,min_zz_end_time,min_time_window,min_global_time,insert_time)

    ems_begin_time = [int(ems_begin_time[i] - min_time) for i in range(len(ems_begin_time))]
    ems_end_time = [int(ems_end_time[i] - min_time) for i in range(len(ems_end_time))]
    zz_begin_time = [[int(zz_begin_time[i][j] - min_time) for j in range(len(zz_begin_time[i]))] for i in
                     range(len(zz_begin_time))]
    zz_end_time = [[int(zz_end_time[i][j] - min_time) for j in range(len(zz_end_time[i]))] for i in
                   range(len(zz_end_time))]
    time_window = [[int(time_window[i][j] - min_time) for j in range(len(time_window[i]))] for i in
                   range(len(time_window))]
    global_time = [[int(global_time[i][j] - min_time) for j in range(len(global_time[i]))] for i in
                   range(len(global_time))]
    insert_time = int(insert_time-min_time)
    max_ems_begin_time = max(ems_begin_time) if ems_begin_time != [] else min_value
    max_ems_end_time = max(ems_end_time) if ems_end_time != [] else min_value
    max_zz_begin_time = max(max(zz_begin_time)) if zz_begin_time != [] else min_value
    max_zz_end_time = max(max(zz_end_time)) if zz_end_time != [] else min_value
    max_time_window = max(max(time_window)) if time_window != [] else min_value
    max_global_time = max(max(global_time)) if global_time != [] else min_value
    max_time = int(
        max(max_ems_begin_time, max_ems_end_time, max_zz_begin_time, max_zz_end_time, max_time_window, max_global_time,insert_time))

    if(insert_time>time_window[-1][-1]):
        logger.error("插单时间不在时间窗内！程序结束")
        exit()

    return ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time, min_time, max_time,insert_time,zz_car_num

def time_process_no_insert(ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time,zz_car_num,logger=Logger):
    '''
    直接使用时间戳时间可能超过求解器的允许的最大数值，因此需要对所有设计时间的参数进行归一化
    根据插入时间更新ems开始时间、更新自制开始时间
    :param ems_begin_time   对应于EMS厂家的最早开始时间，只有一个维度
    :param ems_end_time     对应于EMS厂家的最晚结束时间，只有一个维度
    :param zz_begin_time    对应于自制厂家每辆车的最早开始时间， 维度1，维度2=  厂家，时间
    :param zz_end_time      对应于自制厂家每辆车的最晚结束时间，维度1，维度2=  厂家，时间
    :param time_window      时间窗
    :param  global_time     工厂日历
    :param zz_car_num       自制车的数量
    :return ems_begin_time   对应于EMS厂家的最早开始时间，只有一个维度
    :return ems_end_time     对应于EMS厂家的最晚结束时间，只有一个维度
    :return zz_begin_time    对应于自制厂家每辆车的最早开始时间， 维度1，维度2=  厂家，时间
    :return zz_end_time      对应于自制厂家每辆车的最晚结束时间，维度1，维度2=  厂家，时间
    :return time_window      时间窗
    :return  global_time     工厂日历
    :return zz_car_num       自制车的数量
    '''

    min_ems_begin_time = min(ems_begin_time) if ems_begin_time != [] else max_value
    min_ems_end_time = min(ems_end_time) if ems_end_time != [] else max_value
    min_zz_begin_time = min(min(zz_begin_time)) if zz_begin_time != [] else max_value
    min_zz_end_time = min(min(zz_end_time)) if zz_end_time != [] else max_value
    min_time_window = min(min(time_window)) if time_window != [] else max_value
    min_global_time = min(min(global_time)) if global_time != [] else max_value
    min_time = min(min_ems_begin_time,min_ems_end_time,min_zz_begin_time,min_zz_end_time,min_time_window,min_global_time)

    ems_begin_time = [int(ems_begin_time[i] - min_time) for i in range(len(ems_begin_time))]
    ems_end_time = [int(ems_end_time[i] - min_time) for i in range(len(ems_end_time))]
    zz_begin_time = [[int(zz_begin_time[i][j] - min_time) for j in range(len(zz_begin_time[i]))] for i in
                     range(len(zz_begin_time))]
    zz_end_time = [[int(zz_end_time[i][j] - min_time) for j in range(len(zz_end_time[i]))] for i in
                   range(len(zz_end_time))]
    time_window = [[int(time_window[i][j] - min_time) for j in range(len(time_window[i]))] for i in
                   range(len(time_window))]
    global_time = [[int(global_time[i][j] - min_time) for j in range(len(global_time[i]))] for i in
                   range(len(global_time))]
    max_ems_begin_time = max(ems_begin_time) if ems_begin_time != [] else min_value
    max_ems_end_time = max(ems_end_time) if ems_end_time != [] else min_value
    max_zz_begin_time = max(max(zz_begin_time)) if zz_begin_time != [] else min_value
    max_zz_end_time = max(max(zz_end_time)) if zz_end_time != [] else min_value
    max_time_window = max(max(time_window)) if time_window != [] else min_value
    max_global_time = max(max(global_time)) if global_time != [] else min_value
    max_time = int(
        max(max_ems_begin_time, max_ems_end_time, max_zz_begin_time, max_zz_end_time, max_time_window, max_global_time))

    return ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time, min_time, max_time,zz_car_num

def insert_time_process(ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time,deliver_plan_time,insert_time,logger):

    '''
    时间戳归一化预处理，求解器处理不了太大的数，因此先对数值做归一化预处理
    :param    ems_begin_time        ems开始时间
    :param    ems_end_time          ems结束时间
    :param    zz_begin_time         自制开始时间
    :param    zz_end_time           自制结束时间
    :param    time_window           时间窗
    :param    global_time           全局时间
    :param    deliver_plan_time     插单车辆的开始时间和结束时间
    :param    insert_time           插入时间
    :return    ems_begin_time       ems开始时间
    :return    ems_end_time         ems结束时间
    :return    zz_begin_time        自制开始时间
    :return    zz_end_time          自制结束时间
    :return    time_window          时间窗
    :return    global_time          全局时间
    :return    deliver_plan_time    插单车辆的开始时间和结束时间
    :return    insert_time          插入时间
    '''
    #取所有相关数值中最小的数
    min_ems_begin_time = min(ems_begin_time)  if ems_begin_time != [] else max_value
    min_ems_end_time = min(ems_end_time)  if ems_end_time != [] else max_value
    min_zz_begin_time = min(min(zz_begin_time))  if zz_begin_time != [] else max_value
    min_zz_end_time = min(min(zz_end_time))  if zz_end_time != [] else max_value
    min_time_window = min(min(time_window))  if time_window != [] else max_value
    min_global_time = min(min(global_time))  if global_time != [] else max_value
    min_deliver_plan_time = min(min(min(deliver_plan_time)))  if deliver_plan_time != [] else max_value
    min_time = min(min_ems_begin_time,min_ems_end_time,min_zz_begin_time,min_zz_end_time,min_time_window,min_global_time,min_deliver_plan_time,insert_time)
    #归一化
    ems_begin_time = [int(ems_begin_time[i] - min_time) for i in range(len(ems_begin_time))]
    ems_end_time = [int(ems_end_time[i] - min_time) for i in range(len(ems_end_time))]
    zz_begin_time = [[int(zz_begin_time[i][j] - min_time) for j in range(len(zz_begin_time[i]))] for i in
                     range(len(zz_begin_time))]
    zz_end_time = [[int(zz_end_time[i][j] - min_time) for j in range(len(zz_end_time[i]))] for i in
                   range(len(zz_end_time))]
    time_window = [[int(time_window[i][j] - min_time) for j in range(len(time_window[i]))] for i in
                   range(len(time_window))]
    global_time = [[int(global_time[i][j] - min_time) for j in range(len(global_time[i]))] for i in
                   range(len(global_time))]
    deliver_plan_time = [[[int(deliver_plan_time[i][j][k] - min_time) for k in range(len(deliver_plan_time[i][j]))] for j in range(len(deliver_plan_time[i]))] for i in
                   range(len(deliver_plan_time))]
    #取所有相关数值中最大的数
    insert_time = int(insert_time-min_time)
    max_ems_begin_time = max(ems_begin_time) if ems_begin_time != [] else min_value
    max_ems_end_time = max(ems_end_time) if ems_end_time != [] else min_value
    max_zz_begin_time = max(max(zz_begin_time)) if zz_begin_time != [] else min_value
    max_zz_end_time = max(max(zz_end_time)) if zz_end_time != [] else min_value
    max_time_window = max(max(time_window)) if time_window != [] else min_value
    max_global_time = max(max(global_time)) if global_time != [] else min_value
    max_deliver_plan_time = max(max(max(deliver_plan_time))) if deliver_plan_time != [] else min_value
    max_time = int(
        max(max_ems_begin_time, max_ems_end_time, max_zz_begin_time, max_zz_end_time, max_time_window, max_global_time,max_deliver_plan_time,insert_time))

    if(insert_time>time_window[-1][-1]):      #判断插单时间，如果插单时间在不在时间窗内，则提前结束程序
        logger.error("插单时间不在时间窗内！程序结束")
        exit()
    return ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time, deliver_plan_time,min_time, max_time,insert_time


def repair_time(end_solution_x_total, end_sxt, zz_r, min_time):

    '''
    #还原处理，把归一化的数值还原
    :param end_solution_x_tota  自制最终所有子任务的开始处理时间和处理结束时间，单位为秒
    :param end_sxt  自制最终所有子任务的开始处理时间和处理结束时间，单位为秒
    :param zz_r     自制的真实时间，单位为秒
    :param min_time 最小时间
    '''
    for i in range(len(end_solution_x_total)):
        for j in range(len(end_solution_x_total[i])):
            for k in range(len(end_solution_x_total[i][j])):
                for l in range(len(end_solution_x_total[i][j][k])):
                    for m in range(len(end_solution_x_total[i][j][k][l])):
                        end_solution_x_total[i][j][k][l][m] = end_solution_x_total[i][j][k][l][m] + min_time

    for i in range(len(end_sxt)):
        for j in range(len(end_sxt[i])):
            for k in range(len(end_sxt[i][j])):
                for l in range(len(end_sxt[i][j][k])):
                    for m in range(len(end_sxt[i][j][k][l])):
                        end_sxt[i][j][k][l][m] = end_sxt[i][j][k][l][m] + min_time

    for i in range(len(zz_r)):
        for j in range(len(zz_r[i])):
            for k in range(len(zz_r[i][j])):
                for l in range(len(zz_r[i][j][k])):
                    for m in range(len(zz_r[i][j][k][l])):
                        zz_r[i][j][k][l][m] = zz_r[i][j][k][l][m] + min_time
    return end_solution_x_total, end_sxt, zz_r

def update_insert_time(time_window,no_work_time_re,insert_time):

    '''
    插入时间预处理，更新插入时间:插入时间要去掉两个时间窗之间的间隔
    :param time_window 时间窗
    :param no_work_time_re  两个时间窗之间的间隔
    :param insert_time  插入时间
    :return insert_time     更新后的插入时间
    '''

    for i,tw in enumerate(time_window) :
        if(tw[0]<=insert_time and tw[1]>=insert_time):      #插入时间要去掉两个时间窗之间的间隔
            insert_time = insert_time - no_work_time_re[i]
            break
    return insert_time


def update_zz_time_when_not_splitting_car(time_window, insert_time, zz_begin_time,zz_end_time):
    #

    '''
    不分车时，自制不按发车表排车，开始时间为插单时间
    :param time_window   时间窗
    :param insert_time   插入时间
    :param zz_begin_time    自制开始时间
    :param zz_end_time      自制结束时间
    :return zz_begin_time   自制开始时间
    :return zz_end_time     自制结束时间
    '''

    new_new_begin_time = 0
    new_new_end_time = copy.deepcopy(time_window[-1][-1])
    if insert_time==None or insert_time<= time_window[0][0]:    #插入时间为None或者在时间窗之前，则自制开始时间为时间窗开始时间
        new_new_begin_time = time_window[0][0]
    else:
        for i,tw in enumerate(time_window) :
            if(tw[0]<=insert_time and tw[1]>=insert_time):      #插入时间为None或者在时间窗之前，且插入时间在时间窗内，则自制开始时间为插入时间
                new_new_begin_time = insert_time
                break
            if(i+1 < len(time_window) and tw[1]<=insert_time and insert_time<=time_window[i+1][0]):     #否则为下一个时间窗的开始时间
                new_new_begin_time = time_window[i+1][0]
                break

    for i in range(len(zz_begin_time)):
        for j in range(len(zz_begin_time[i])):
            zz_begin_time[i][j] = new_new_begin_time
            zz_end_time[i][j] = new_new_end_time



    return zz_begin_time,zz_end_time


def insert_fun(ems_goods_num, ems_begin_time, ems_end_time, ems_job_type, ems_goods, zz_goods_num,
                    zz_begin_time,
                    zz_end_time, zz_job_type, zz_goods, fu_dong_EMS, fu_dong_zz, rong_liang_EMS,
                    rong_liang_zz,
                    zhuan_hua_EMS, zhuan_hua_zz, time_window, dis, zz_car_num, t1, t2, EMS_interval_time,
                    zz_interval_time, ems_priority, zz_priority, deliver_plan_time, detail_port_num, detail_id_arr,
                    insert_time, global_time, box_flow_value, ems_detail_add_date,zz_detail_add_date,is_splitting_car,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map,logger=Logger):
    '''
    主函数，直接用这个就行
    :param ems_goods_num:EMS的货物量，第一个维度为厂家，第二个维度为订单详情
    :param ems_begin_time:对应于EMS厂家的最早开始时间，只有一个维度
    :param ems_end_time:对应于EMS厂家的最晚结束时间，只有一个维度
    :param ems_job_type:对应于EMS货物的形态，1是件箱，0是栈板，第一个维度为厂家，第二个维度为订单详情
    :param c:对应于EMS的可用通道，第一个为厂家，第二个维度为订单详情，第三个维度为货物类别，不同类别对应于不同的通道
    :param V_j:输入到EMS求解的速度参数
    :param ems_goods:EMS的货物数量
    :param zz_goods_num:自制的货物量，这回既有件箱又有栈板，第一个维度为厂家，第二个维度为订单详情
    :param zz_begin_time:对应于自制厂家的最早开始时间，只有一个维度
    :param zz_end_time:对应于自制厂家的最晚结束时间，只有一个维度
    :param zz_job_type:对应于自制货物的形态，1是件箱，0是栈板，第一个维度为厂家，第二个维度为订单详情
    :param zz_goods:自制的货物数量
    :param s_c:对应于自制的可用通道，第一个为厂家，第二个维度为订单详情，第三个维度为货物类别，不同类别对应于不同的通道
    :param V_se_j:输入到自制求解的速度参数，V_se_j[0]和V_se_j[1]与V_j[0]和V_j[2]数值上是一样的
    :param fu_dong_EMS:对应于厂家的浮动系数，只有一个维度(EMS)
    :param fu_dong_zz:对应于厂家的浮动系数，只有一个维度(自制)
    :param rong_liang_EMS:对应于厂家的车辆容量，只有一个维度(EMS)
    :param rong_liang_zz:对应于厂家的车辆容量，只有一个维度(自制)
    :param zhuan_hua_EMS:对应于厂家的转换系数，只有一个维度(EMS)
    :param zhuan_hua_zz:对应于厂家的转换系数，只有一个维度(自制)
    :param a_c:栈板的总通道数量
    :param p_num:EMS的件箱总通道数量
    :param time_window:工作时间窗
    :param dis:打折系数
    :param zz_car_num:自制车的数量
    :param t1:EMS求解时间
    :param t2:自制求解时间
    :param EMS_interval_time:EMS发车间隔时间
    :param zz_interval_time:自制发车间隔时间
    :param ems_priority ems优先级
    :param zz_priority 自制优先级
    :param deliver_plan_time     #插单货物的时间窗    维度1，维度2，维度3 =  厂家，件箱/栈板，时间
    :param detail_port_num       #插单货物的通道号    维度1，维度2 =  厂家，通道号
    :param detail_id_arr         #插单货物的序号      维度1 =  序号
    :param insert_time   插入时间
    :param global_time   全局时间
    :param box_flow_value  流量限制
    :param ems_detail_add_date  ems订单生成时间
    :param zz_detail_add_date    自制订单生成时间
    :param is_splitting_car     是否分车
    :param ems_floor    ems楼层参数
    :param zz_floor    自制楼层参数
    :param floor_speed_map  楼层速度参数
    :param floor_port_num_map   楼层通道参数
    :param floor_delivery_num_map   楼层最大通道数参数
    :param port_assignment_map  每几个货物分配多少通道

    :return:end_solution_x_total:EMS所有子任务的开始处理时间和处理结束时间，单位为秒
     solution_bool_sub_job:该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理(EMS)
     solution_bool_C:该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用(EMS)
     end_sxt:自制所有子任务的开始处理时间和处理结束时间，单位为秒
     sbsj:该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理(自制)
     sbc:该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用(自制)
     car:每辆车装载的货物量(EMS在前，自制在后，件箱和栈板的数量)
     job_re:记录每辆车装载的货物编号(对应于car，也对应于good_nums)
     job_total:EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
     job_type_total:EMS货物形态 0可代表栈板，1代表件箱
     job_se_total:自制任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量
     job_se_type_total:自制货物形态 0可代表栈板，1代表件箱
     goods_num:每辆车装载的货物量(EMS在前，自制在后，对应于箱内的数量，不是件箱栈板的数量)
     total_d_num:每辆车订单详情对应的件箱栈板数量[a,b]，a对应件箱的数量，b对应栈板的数量(EMS在前，自制在后)
     total_d_goods:每辆车订单详情对应的货物的数量[a,b]，a对应件箱位置的货物数量，b对应栈板位置的货物数量(EMS在前，自制在后)
     zz_r:自制的真实时间
     no_car_re：缺车的订单详情
    '''

    # deliver_plan_time, detail_port_num, detail_id_arr = remove_du(deliver_plan_time, detail_port_num, detail_id_arr)
    # 主要处理重排的函数
    # random_ems_index,random_zz_index = get_random_index(p_num,s_c)

    # EMS截止时间空值0值处理(处理为最后一个时间窗截止时间)
    ems_end_time = get_ems_end_time(time_window,ems_end_time)

    # 不分车模式自制截止时间空值0值处理(处理为最后一个时间窗截止时间)
    if is_splitting_car == False:
        zz_end_time = get_ems_end_time(time_window,zz_end_time)

    # 自制车辆填充预处理，如果不分车模式自制车辆为空，则按照更新开始时间更新车辆数量为1
    zz_begin_time, zz_end_time,zz_car_num = get_updated_without_start_table(zz_begin_time, zz_end_time,zz_car_num)

    # 深拷贝，防止因为版本不同出现深拷贝bug
    detail_id_arr = [copy.deepcopy(detail_id_arr[i]) for i in range(len(detail_id_arr))]

    # 开始时间更新，将ems开始时间和自制每个车次的开始时间更新为max(insert_time,begin_time),若insert_time>end_time,取begin_time=ens_time（导致排不进去）
    ems_begin_time, zz_begin_time = get_start_time(ems_begin_time, ems_end_time, zz_begin_time, zz_end_time,
                                                   insert_time)

    # 时间戳归一化预处理，所有时间减去minTime，达到数据平移
    # 若insertTime>最后一个时间窗的结束时间，则输出"插单时间不在时间窗内！程序结束"
    ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time,deliver_plan_time, min_time, max_time,insert_time = insert_time_process(
        ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time,deliver_plan_time,insert_time,logger)

    # 工厂日历可用时间和时间窗时间交集处理，无交集或工厂日历为空程序结束
    time_window = interval_Intersection(time_window, global_time,logger)

    # 连续时间窗合并
    time_window = time_window_combie(time_window)

    # 资源锁定时间段处理，根据锁定资源时间更新ems开始时间、更新自制开始时间
    ems_time_lock, ems_port_lock, ems_id_lock, zz_time_lock, zz_port_lock, zz_id_lock, zz_d1, ems_begin_time = get_insert_start_time(insert_time,
                                                                                                            deliver_plan_time,
                                                                                                            detail_port_num,
                                                                                                            detail_id_arr,
                                                                                                            ems_begin_time,
                                                                                                            EMS_interval_time,
                                                                                                            zz_interval_time)

    # 按厂家优先级将所有参数重新排序
    # 不分车模式将间隔时间直接替换成0，分车模式按入参间隔时间设置
    # 把按优先级排列后的对同一交付对象自制的发车时间升序排列
    # 最后处理分配多口箱数阈值port_assignment_map，完善成从1口到n+1口的件箱阈值
    ems_goods_num, ems_begin_time, ems_end_time, ems_job_type, ems_goods, zz_goods_num, \
    zz_begin_time, zz_end_time, zz_job_type, zz_goods, fu_dong_EMS, fu_dong_zz, \
    rong_liang_EMS, rong_liang_zz, zhuan_hua_EMS, zhuan_hua_zz, EMS_interval_time, \
    zz_interval_time, index_original_ems, index_original_zz, zz_car_num,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map = priority_process(ems_priority,
                                                                                            zz_priority,
                                                                                            ems_goods_num,
                                                                                            ems_begin_time,
                                                                                            ems_end_time,
                                                                                            ems_job_type,
                                                                                            ems_goods,
                                                                                            zz_goods_num,
                                                                                            zz_begin_time,
                                                                                            zz_end_time,
                                                                                            zz_job_type,
                                                                                            zz_goods,
                                                                                            fu_dong_EMS,
                                                                                            fu_dong_zz,
                                                                                            rong_liang_EMS,
                                                                                            rong_liang_zz,
                                                                                            zhuan_hua_EMS,
                                                                                            zhuan_hua_zz,
                                                                                            EMS_interval_time,
                                                                                            zz_interval_time,
                                                                                            zz_car_num,
                                                                                            box_flow_value, ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map,time_window,is_splitting_car
                                                                                            )

    # 深拷贝，防止因为版本不同出现深拷贝bug
    detail_id_arr = [copy.deepcopy(detail_id_arr[i]) for i in range(len(detail_id_arr))]

    # 重排车辆id更新
    detail_id_arr = get_new_detail_id_arr(detail_id_arr,index_original_ems,index_original_zz)

    # 自制发车表排序预处理,发车表时间从小到大排序，priority_process已经处理过自制车次顺序，这一步属于重复操作
    zz_begin_time, zz_end_time, zz_car_num = get_ini_zz_time_car(zz_begin_time, zz_end_time,
                                                                 zz_car_num)

    # 自制车辆优先级预处理，后续算法会优先选择发车时间在时间窗内且晚于插单时间的车
    if insert_time != None:
        zz_car_num,zz_begin_time, zz_end_time  = insert_sort_zz_time(zz_begin_time, zz_end_time,zz_car_num,time_window,insert_time)
    else:
        # 自制车辆优先级预处理，后续算法会优先选择发车时间在时间窗内的车
        zz_car_num, zz_begin_time, zz_end_time = sort_zz_time(zz_begin_time, zz_end_time, zz_car_num,time_window)

    # EMS开始结束时间修正，EMS若不在时间窗范围内开始结束时间取时间窗的最早开始时间和最晚结束时间，自制已处理过无需处理
    ems_begin_time, ems_end_time = start_end_time_process(ems_begin_time, ems_end_time,
                                                          time_window,logger)

    # 时间窗连续预处理，时间窗的时间可能不是连续的，需要将不连续的时间去掉，使其变的连续，方便时间窗的计算
    # 将ems时间移动，在需要移动的时间窗范围内的ems开始结束时间也需要移动，在时间窗模型计算完后，再把解进行还原
    ems_n_start_time, ems_n_d_list, no_work_time_re, work_time_list, interval_time = time_window_process(time_window, ems_begin_time,
                                                                                          ems_end_time)

    if (is_splitting_car==False):
        # 不分车装车模型
        job_total, job_type_total, job_re_ems, goods_num_ems, ems_car_d_num, ems_car_d_type, ems_car_d_goods_num, _, _, order_sequence_ems = load_without_splitting_car(ems_goods_num,ems_job_type,ems_goods,ems_detail_add_date)    #不分车模式下的装车，假设车内的货物数量是无限的，把所有货物按照顺序加到车内
        job_se_total, job_se_type_total, zz_job_re, zz_goods_num_new, zz_car_d_num, zz_car_d_type, zz_car_d_goods_num, no_car_re, no_job_data_re,order_sequence_zz = load_without_splitting_car(zz_goods_num,zz_job_type,zz_goods,zz_detail_add_date)   #    不分车模式下的装车，假设车内的货物数量是无限的，把所有货物按照顺序加到车内
    else:
        # EMS装车模型
        job_total, job_type_total, job_re_ems, goods_num_ems, ems_car_d_num, ems_car_d_type, ems_car_d_goods_num = load_fun_3(
            ems_goods_num, ems_job_type, len(ems_goods_num), fu_dong_EMS, rong_liang_EMS, zhuan_hua_EMS,
            ems_goods)

        # 自制装车模型
        job_se_total, job_se_type_total, zz_job_re, zz_goods_num_new, zz_car_d_num, zz_car_d_type, zz_car_d_goods_num, no_car_re, no_job_data_re = load_se(
            zz_goods_num, zz_job_type, rong_liang_zz, zhuan_hua_zz, zz_goods, zz_car_num,t1,logger)
        order_sequence_ems = []
        order_sequence_zz = []

    zz_begin_time, zz_end_time, zz_car_num = remove_lock_time(deliver_plan_time, detail_port_num, detail_id_arr,
                                                              insert_time, zz_begin_time, zz_end_time, zz_car_num,
                                                              zz_interval_time, job_se_total, job_se_type_total, dis,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,is_splitting_car)    #移除重复锁单时间



    job_se_total, job_se_type_total, zz_job_re, zz_goods_num_new, zz_car_d_num, zz_car_d_type, zz_car_d_goods_num, no_car_re_1,no_job_data_re1, zz_begin_time, zz_end_time, zz_car_num = zz_process_1(
        job_se_total, job_se_type_total, zz_job_re, zz_goods_num_new, zz_car_d_num, zz_car_d_type, zz_car_d_goods_num,
        zz_car_num, zz_begin_time, zz_end_time) #自制删车预处理

    if (is_splitting_car==False):
        zz_begin_time,zz_end_time = update_zz_time_when_not_splitting_car(time_window, insert_time, zz_begin_time,zz_end_time)  #不分车时，自制不按发车表排车，开始时间为插单时间

    car_time_before = insert_get_se_car_to_time_before(job_se_total, zz_begin_time, zz_end_time,
                                                zz_car_num,insert_time)  # (弃用)该函数用于得到还未经time_window_process_se函数处理过的自制发车时间，主要作用就是给排的自制车分配发车的开始时间和结束时间，然后方便get_end_zz_time函数的使用

    zz_n_start_time, zz_n_d_list = time_window_process_se(time_window, zz_begin_time,
                                                          zz_end_time)  # 时间窗的时间可能不是连续的，我们需要将不连续的时间去掉，使其变的连续，方便时间窗的计算，就像这样[[540, 740],[740, 940],[1140, 1340]] -> [[540, 740],[740, 940],[940, 1140]]
    # 将时间向前移，在那个需要移动的时间窗范围内的时间也需要移动，在时间窗模型计算完后，再把解进行还原
    # 这个函数处理了自制发车表的开始时间和结束时间

    insert_time = update_insert_time(time_window,no_work_time_re,insert_time)    #插入时间预处理，更新插入时间,插入时间要去掉两个时间窗之间的间隔

    car_time = insert_get_se_car_to_time(job_se_total, zz_n_start_time, zz_n_d_list,
                                  zz_car_num,insert_time)  # 该函数就是把处理后的自制发车表时间分配给排的自制车，在功能的实现上和get_se_car_to_time_before是一样的，但是得到的时间是经过time_window_process_se处理过的


    sxt, sbsj, sbc, sbc_n, solution_x_total, solution_bool_sub_job, solution_bool_C, end_sxt_ = insert_solve_all(job_se_total, job_se_type_total, dis, car_time, t2, zz_interval_time,
                                     rong_liang_zz, zhuan_hua_zz, box_flow_value, zz_priority, max_time,floor_speed_map,is_splitting_car,floor_port_num_map,ems_floor,zz_floor,port_assignment_map, floor_delivery_num_map,
                                     job_total, ems_n_d_list, job_type_total, ems_n_start_time,
                                     EMS_interval_time, rong_liang_EMS,zhuan_hua_EMS,
                                     ems_priority,work_time_list, interval_time,ems_time_lock, ems_port_lock, ems_id_lock, zz_time_lock, zz_port_lock, zz_id_lock, zz_d1, zz_n_start_time, zz_n_d_list,zz_car_num,zz_begin_time,zz_end_time,logger)


    end_solution_x_total = get_end_time(solution_x_total, solution_bool_sub_job, no_work_time_re,
                                        work_time_list)  # 该函数用于得到加入不工作时间后最终的时间窗结果

    end_sxt = get_end_time(sxt, sbsj, no_work_time_re, work_time_list)  # 该函数用于得到加入不工作时间后最终的时间窗结果

    zz_r = copy.deepcopy(end_sxt)  # 保存自制的真实作业时间

    if (is_splitting_car==True):
        end_sxt = copy.deepcopy(end_sxt_)  # 保存自制的真实作业时间

    car = job_total + job_se_total  # 得到最终的装车模型的输出（EMS在前，自制在后）

    goods_num = goods_num_ems + zz_goods_num_new  # 得到最终的货物内部数量的输出

    solution_bool_C = solution_c_ems_process(end_solution_x_total, job_total, job_type_total, solution_bool_sub_job,
                                             solution_bool_C, dis,floor_speed_map,ems_floor,floor_port_num_map)  # 通道资源过多的处理



    sbc = solution_c_zz_process(zz_r, job_se_total, job_se_type_total, sbsj, sbc,
                                dis,floor_speed_map,zz_floor,floor_port_num_map)  # 通道资源过多的处理
    # 对自制下标的处理，方便EMS和自制下标的合并
    for i in range(len(zz_job_re)):
        for j in range(len(zz_job_re[i])):
            for k in range(len(zz_job_re[i][j])):
                for p in range(len(zz_job_re[i][j][k])):
                    zz_job_re[i][j][k][p][0] += len(job_re_ems)

    # 将自制和EMS的下标合并
    job_re = job_re_ems + zz_job_re

    # 对下标进行最终的处理，得到输出需要的下标
    job_re_end = process_job_re(job_re)


    # 对货物数量和货物内部数量的处理，得到需要的输出
    total_d_num, total_d_goods = d_process(job_re, job_re_end, ems_car_d_num, ems_car_d_type, ems_car_d_goods_num,
                                           zz_car_d_num, zz_car_d_type, zz_car_d_goods_num)


    #优先级处理，把排序后的优先级还原
    for i in range(len(job_re_end)):
        for j in range(len(job_re_end[i])):
            for k in range(len(job_re_end[i][j])):
                for p in range(len(job_re_end[i][j][k])):
                    if i < len(job_re_ems):
                        job_re_end[i][j][k][p][0] = index_original_ems[i]
                    else:
                        f = job_re_end[i][j][k][p][0]
                        job_re_end[i][j][k][p][0] = index_original_zz[f - len(job_re_ems)] + len(job_re_ems)

    if bool(no_car_re):     #自制下标的序号需要加上ems的交付对象数量
        for i in range(len(no_car_re)):
            f = no_car_re[i][0]
            no_car_re[i][0] = index_original_zz[f] + len(job_re_ems)

    if bool(no_car_re_1):       #自制下标的序号需要加上ems的交付对象数量
        for i in range(len(no_car_re_1)):
            f = no_car_re_1[i][0]
            no_car_re_1[i][0] = index_original_zz[f] + len(job_re_ems)

    no_car_re = no_car_re + no_car_re_1                 #数据拼接
    no_job_data_re = no_job_data_re + no_job_data_re1       #数据拼接
    new_no_job_data_re = []
    new_no_car_re = []
    re_s = set()
    for i in range(len(no_car_re)):
        if tuple(no_car_re[i]) not in re_s:                     #去重
            re_s.add(tuple(no_car_re[i]))
            new_no_car_re.append(copy.deepcopy(no_car_re[i]))
            new_no_job_data_re.append(copy.deepcopy(no_job_data_re[i]))
        else:
            new_no_job_data_re[new_no_car_re.index(no_car_re[i])][0] += copy.deepcopy(no_job_data_re[i][0])
            new_no_job_data_re[new_no_car_re.index(no_car_re[i])][1] += copy.deepcopy(no_job_data_re[i][1])

    end_solution_x_total, end_sxt, zz_r = repair_time(end_solution_x_total, end_sxt, zz_r, min_time)    #把归一化的数值还原

    return end_solution_x_total, solution_bool_sub_job, solution_bool_C, end_sxt, sbsj, sbc, car, job_re_end, job_total, \
           job_type_total, job_se_total, job_se_type_total, goods_num, total_d_num, total_d_goods, zz_r, new_no_car_re,new_no_job_data_re

def time_window_combie(time_window):

    '''
    一个时间窗间隔的结束和另一个时间窗间隔的开始相接则将两个时间窗间隔拼接
    :param time_window: 时间窗
    :return time_window 拼接后的时间窗
    '''

    if len(time_window)<2:      #只有一个间隔则直接返回
        return time_window
    new_time_window = []
    start = 0
    for end in range(1,len(time_window)):       #只有一个间隔则直接返回
        if time_window[end][0] == time_window[end-1][1] and end!=len(time_window)-1:        #开始时间和结束时间相接
            continue
        if time_window[end][0] == time_window[end - 1][1] and end == len(time_window) - 1:      #相接且为最后一个时间段
            new_time_window.append([time_window[start][0], time_window[end][1]])
        if time_window[end][0] != time_window[end - 1][1] and end != len(time_window) - 1:        #不相接且不为最后一个时间段
            new_time_window.append([time_window[start][0],time_window[end-1][1]])
            start = end
        if time_window[end][0] != time_window[end - 1][1] and end == len(time_window) - 1:   #不相接且为最后一个时间段
            new_time_window.append([time_window[start][0],time_window[end-1][1]])
            new_time_window.append([time_window[end][0],time_window[end][1]])
    return new_time_window

def get_start_time(ems_begin_time, ems_end_time, zz_begin_time, zz_end_time,insert_time):

    '''
    开始时间更新，根据插入时间更新ems开始时间、更新自制开始时间
    :param ems_begin_time   对应于EMS厂家的最早开始时间，只有一个维度
    :param ems_end_time     对应于EMS厂家的最晚结束时间，只有一个维度
    :param zz_begin_time    对应于自制厂家每辆车的最早开始时间， 维度1，维度2 =  厂家，时间
    :param zz_end_time      对应于自制厂家每辆车的最晚结束时间，维度1，维度2 =  厂家，时间
    :param insert_time      插入时间
    :return new_ems_begin_time      更新后的ems开始时间
    :return new_zz_begin_time        更新后的自制开始时间
    '''

    new_ems_begin_time = []
    new_zz_begin_time = []

    for i in range(len(ems_begin_time)):
        if insert_time >=ems_begin_time[i] and insert_time <= ems_end_time[i]:  #如果插入时间在开始时间之前，在结束时间后，则将开始时间置为插入时间
            new_ems_begin_time.append(insert_time)
        elif insert_time <ems_begin_time[i]:                                    #如果插入时间在开始时间之前,则使用原开始时间
            new_ems_begin_time.append(ems_begin_time[i])
        else:                                                                   #如果插入时间在开始时间之后，则使用开始时间和结束时间一致
            new_ems_begin_time.append(ems_end_time[i])

    for i in range(len(zz_begin_time)):                                          #自制同理，但是自制的格式不一样，所以多了一个子数组
        sub_new_zz_begin_time = []
        for j in range(len(zz_begin_time[i])):
            if insert_time >=zz_begin_time[i][j]  and insert_time <= zz_end_time[i][j] :
                sub_new_zz_begin_time.append(insert_time)
            elif insert_time < zz_begin_time[i][j]:
                sub_new_zz_begin_time.append(zz_begin_time[i][j])
            else:
                sub_new_zz_begin_time.append(zz_end_time[i][j])
        new_zz_begin_time.append(sub_new_zz_begin_time)

    return new_ems_begin_time, new_zz_begin_time

def get_random_index_(p_num,s_c):
    #c:自制通道
    #c:ems通道

    random_ems_index = [i for i in range(p_num)]
    random.shuffle(random_ems_index)

    if s_c:
        num_zz_index = max([len(s_c[i][0][0])*s_c[i][0][0][0]//2 for i in range(len(s_c))])
    else:
        num_zz_index = 0
    random_zz_index =  [i for i in range(num_zz_index)]
    random.shuffle(random_zz_index)

    return random_ems_index,random_zz_index

def get_random_index(floor_port_num_map):
    #c:自制通道
    #c:ems通道
    random_index = {}
    for port_num in floor_port_num_map:
        order_index = [i for i in range(floor_port_num_map[port_num])]
        random.shuffle(order_index)
        random_index[port_num] = order_index

    return random_index

def get_zz_cargo_num(job_data,job_type,c):
    total_zz_cargo_num = []
    total_ems_cargo_num = []

    for i in range(len(job_data)):
        sub_total_zz_cargo_num = 0
        sub_total_ems_cargo_num = 0
        for j in range(len(job_data[i])):
            for k in range(len(job_data[i][j])):
                for e in range(len(job_data[i][j][k])):
                    if job_type[i][j][k][e] == 1:
                        if c[i][0][0][0] == 1:
                            sub_total_zz_cargo_num += job_data[i][j][k][e]
                        else:
                            sub_total_ems_cargo_num += job_data[i][j][k][e]

        total_zz_cargo_num.append(sub_total_zz_cargo_num)
        total_ems_cargo_num.append(sub_total_ems_cargo_num)


    return total_zz_cargo_num,total_ems_cargo_num

def get_cargo_num_(job_data,job_type):

    '''
    统计件箱个数
    :param job_data   任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量
    :param job_type     货物形态 0可代表栈板，1代表件箱
    :return total_cargo_num  每个厂家的件箱数量
    '''

    total_cargo_num = []

    for i in range(len(job_data)):
        sub_total_cargo_num = 0
        for j in range(len(job_data[i])):
            for k in range(len(job_data[i][j])):
                for e in range(len(job_data[i][j][k])):
                    if job_type[i][j][k][e] == 1:           #如果是件箱，则累计数量
                        sub_total_cargo_num += job_data[i][j][k][e]

        total_cargo_num.append(sub_total_cargo_num)

    return total_cargo_num

def get_ems_cargo_num(job_data,job_type):
    total_ems_cargo_num = []

    for i in range(len(job_data)):
        sub_total_ems_cargo_num = 0
        for j in range(len(job_data[i])):
            for k in range(len(job_data[i][j])):
                for e in range(len(job_data[i][j][k])):
                    if job_type[i][j][k][e] == 1:
                        sub_total_ems_cargo_num += job_data[i][j][k][e]
        total_ems_cargo_num.append(sub_total_ems_cargo_num)


    return total_ems_cargo_num

def update_floor_port_num_map(floor_port_num_map):
    for port_num in floor_port_num_map:
        floor_port_num_map[port_num] = [1 for i in range(floor_port_num_map[port_num])]

def get_updated_without_start_table(zz_begin_time, zz_end_time,zz_car_num):
    '''
    自制车辆填充预处理，如果自制车辆为空，则按照不分车模式处理，把开始时间、结束时、车辆数量的格式更改为每个交付对象一个
    :param zz_begin_time:对应于自制厂家每辆车的最早开始时间， 维度1，维度2=  厂家，时间
    :param zz_end_time:对应于自制厂家每辆车的最晚结束时间，维度1，维度2=  厂家，时间
    :param zz_car_num:自制车的数量
    :return zz_begin_time 新的自制开始时间
    :return zz_end_time 新的自制结束时间
    :return zz_car_num 新的自制车辆数量
    '''
    if zz_car_num == []:
        for i in range(len(zz_begin_time)) :
            zz_begin_time[i] = [zz_begin_time[i]]
            zz_end_time[i] = [zz_end_time[i]]
            zz_car_num.append([1])

    return zz_begin_time, zz_end_time, zz_car_num

def   walkthrough_fun(ems_goods_num, ems_begin_time, ems_end_time, ems_job_type, ems_goods, zz_goods_num, zz_begin_time,
             zz_end_time, zz_job_type, zz_goods, fu_dong_EMS, fu_dong_zz, rong_liang_EMS, rong_liang_zz,
             zhuan_hua_EMS, zhuan_hua_zz, time_window, dis, zz_car_num, t1, t2, EMS_interval_time,
             zz_interval_time, ems_priority, zz_priority, global_time, box_flow_value,
            insert_time,ems_detail_add_date,zz_detail_add_date,is_splitting_car,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map,logger):
    # logger.info("jiasod")
    # logger.error("asjdoaisdjo")
    '''
    主函数，直接用这个就行
    :param ems_goods_num:EMS的货物量；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    :param ems_begin_time:对应于EMS厂家的最早开始时间，只有一个维度
    :param ems_end_time:对应于EMS厂家的最晚结束时间，只有一个维度
    :param ems_job_type:对应于EMS货物的形态，1是件箱，0是栈板，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，订单类型
    :param c:对应于EMS的可用通道；维度1，维度2，维度3，维度4 = 厂家，订单，通道类型，通道 ；通道类型中前一个维度都是件箱的，后一个维度都是栈板的，如c = [[[[1, 1, 1, 1], [1, 1]]]]中[1, 1, 1, 1]表示件箱可用的通道，[1,1]表示栈板可用的通道(弃用)
    :param V_j:输入到EMS求解的速度参数,单位:数量/秒，[栈板速度，件箱速度，自制速度](弃用)
    :param ems_goods:EMS的货物数量；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物数量
    :param zz_goods_num:自制的货物量，其中既有件箱又有栈板，维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物量
    :param zz_begin_time:对应于自制厂家每辆车的最早开始时间， 维度1，维度2=  厂家，时间
    :param zz_end_time:对应于自制厂家每辆车的最晚结束时间，维度1，维度2=  厂家，时间
    :param zz_job_type:对应于自制货物的形态，1是件箱，0是栈板，第一个维度为厂家，第二个维度为订单详情
    :param zz_goods:自制的货物数量；维度1，维度2，维度3，维度4 =  厂家，订单，订单详情，货物数量
    :param s_c:对应于自制的可用通道；维度1，维度2，维度3 =  厂家，订单，货物类型，通道类型和数量；[0,1]表示1楼，[1,0]表示-1楼； 第三个维度前件箱，后栈板；如 s_c = [[[[1, 0, 1, 0], [1, 1, 1]]], [[[0, 1], [1, 1, 1]]]]表示第一个厂家安排了负1楼件箱通道2个,栈板通道3个;第二个厂家安排了1楼件箱通道1个,栈板通道3个(弃用)
    :param V_se_j:输入到自制求解的速度参数，单位:数量/秒，[栈板速度，自制速度，件箱速度](弃用)
    :param fu_dong_EMS:对应于厂家的浮动系数，只有一个维度(EMS)
    :param fu_dong_zz:对应于厂家的浮动系数，只有一个维度(自制)
    :param rong_liang_EMS:对应于厂家的车辆容量，只有一个维度(EMS)
    :param rong_liang_zz:对应于厂家的车辆容量，只有一个维度(自制)
    :param zhuan_hua_EMS:对应于厂家的转换系数，只有一个维度(EMS)
    :param zhuan_hua_zz:对应于厂家的转换系数，只有一个维度(自制)
    :param a_c:栈板的总通道数量(弃用)
    :param p_num:EMS的件箱总通道数量(弃用)
    :param time_window:工作时间窗；维度1，维度2 =  某个时间间隔，时间
    :param dis:打折系数(弃用)
    :param zz_car_num:自制车的数量
    :param t1:EMS求解时间(弃用)
    :param t2:自制求解时间(弃用)
    :param EMS_interval_time:EMS发车间隔时间
    :param zz_interval_time:自制发车间隔时间
    :param ems_priority ems优先级
    :param zz_priority 自制优先级
    :param deliver_plan_time     #插单货物的时间窗    维度1，维度2，维度3 =  厂家，件箱/栈板，时间
    :param detail_port_num       #插单货物的通道号    维度1，维度2 =  厂家，通道号
    :param detail_id_arr         #插单货物的序号      维度1 =  序号
    :param insert_time   插入时间
    :param global_time   全局时间
    :param box_flow_value  流量限制
    :param ems_detail_add_date  ems订单生成时间
    :param zz_detail_add_date    自制订单生成时间
    :param is_splitting_car     是否分车
    :param ems_floor    ems楼层参数
    :param zz_floor    自制楼层参数
    :param floor_speed_map  楼层速度参数
    :param floor_port_num_map   楼层通道参数
    :param floor_delivery_num_map   楼层最大通道数参数
    :param port_assignment_map  每几个货物分配多少通道

    :return:end_solution_x_total:EMS所有子任务的开始处理时间和处理结束时间，单位为秒
     solution_bool_sub_job:该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理(EMS)
     solution_bool_C:该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用(EMS)
     end_sxt:自制所有子任务的开始处理时间和处理结束时间，单位为秒
     sbsj:该项对应某一个子任务是否被处理，若为1则被处理，若为0则没被处理(自制)
     sbc:该项对应子任务的通道使用情况，其中为1则该通道被使用，为0则没被使用(自制)
     car:每辆车装载的货物量(EMS在前，自制在后，件箱和栈板的数量)
     job_re:记录每辆车装载的货物编号(对应于car，也对应于good_nums)
     job_total:EMS任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量,同时任务的优先级默认从高到低依次排列
     job_type_total:EMS货物形态 0可代表栈板，1代表件箱
     job_se_total:自制任务的具体信息，即货物数量，该项包含n个任务和各个任务对应的子任务的货物数量
     job_se_type_total:自制货物形态 0可代表栈板，1代表件箱
     goods_num:每辆车装载的货物量(EMS在前，自制在后，对应于箱内的数量，不是件箱栈板的数量)
     total_d_num:每辆车订单详情对应的件箱栈板数量[a,b]，a对应件箱的数量，b对应栈板的数量(EMS在前，自制在后)
     total_d_goods:每辆车订单详情对应的货物的数量[a,b]，a对应件箱位置的货物数量，b对应栈板位置的货物数量(EMS在前，自制在后)
     zz_r:自制的真实时间
     no_car_re：缺车的订单详情
     no_job_data_re: 被丢弃的车中的货物，前件箱，后栈板
    '''


    ems_end_time = get_ems_end_time(time_window,ems_end_time) #EMS跨天预处理
    if is_splitting_car == False:
        zz_end_time = get_ems_end_time(time_window,zz_end_time) #EMS跨天预处理
    zz_begin_time, zz_end_time,zz_car_num = get_updated_without_start_table(zz_begin_time, zz_end_time,zz_car_num)  #自制车辆填充预处理，如果自制车辆为空，则按照不分车模式处理，把开始时间、结束时、车辆数量的格式更改为每个交付对象一个
    if insert_time!= None:
        ems_begin_time, zz_begin_time = get_start_time(ems_begin_time, ems_end_time, zz_begin_time, zz_end_time,insert_time)#根据插入时间更新ems开始时间、更新自制开始时间
        ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time, min_time, max_time,insert_time,zz_car_num = time_process(
            ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time,insert_time,zz_car_num, logger=Logger) #时间戳归一化预处理
    else:
        ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time, min_time, max_time,zz_car_num = time_process_no_insert(
            ems_begin_time, ems_end_time, zz_begin_time, zz_end_time, time_window, global_time,zz_car_num,logger=Logger) #时间戳归一化预处理

    time_window = interval_Intersection(time_window, global_time,logger) #时间窗排序
    time_window = time_window_combie(time_window)#时间窗合并

    ems_goods_num, ems_begin_time, ems_end_time, ems_job_type, ems_goods, zz_goods_num, \
    zz_begin_time, zz_end_time, zz_job_type, zz_goods, fu_dong_EMS, fu_dong_zz, \
    rong_liang_EMS, rong_liang_zz, zhuan_hua_EMS, zhuan_hua_zz, EMS_interval_time, \
    zz_interval_time, index_original_ems, index_original_zz, zz_car_num,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map = priority_process(ems_priority,
                                                                                                        zz_priority,
                                                                                                        ems_goods_num,
                                                                                                        ems_begin_time,
                                                                                                        ems_end_time,
                                                                                                        ems_job_type,
                                                                                                        ems_goods,
                                                                                                        zz_goods_num,
                                                                                                        zz_begin_time,
                                                                                                        zz_end_time,
                                                                                                        zz_job_type,
                                                                                                        zz_goods,
                                                                                                        fu_dong_EMS,
                                                                                                        fu_dong_zz,
                                                                                                        rong_liang_EMS,
                                                                                                        rong_liang_zz,
                                                                                                        zhuan_hua_EMS,
                                                                                                        zhuan_hua_zz,
                                                                                                        EMS_interval_time,
                                                                                                        zz_interval_time,
                                                                                                        zz_car_num,
                                                                                                        box_flow_value,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map,time_window,is_splitting_car) #厂家优先级预处理



    zz_begin_time, zz_end_time, zz_car_num = get_ini_zz_time_car(zz_begin_time, zz_end_time,
                                                                 zz_car_num)  # 自制发车表排序预处理，自制的发车表时间是乱的，需要进行一个初步处理，让发车表时间从小到大排序，发车表的车辆也依次对应起来



    if insert_time != None:
        zz_car_num,zz_begin_time, zz_end_time = insert_sort_zz_time(zz_begin_time, zz_end_time,zz_car_num,time_window,insert_time) #自制车辆优先级预处理
    else:
        zz_car_num, zz_begin_time, zz_end_time = sort_zz_time(zz_begin_time, zz_end_time, zz_car_num,time_window) #自制车辆优先级预处理

    ems_begin_time, ems_end_time = start_end_time_process(ems_begin_time, ems_end_time,
                                                          time_window,logger)  #开始结束时间预处理 由于EMS给出的开始时间和deadline可能不在时间窗的范围内，因此这里做出处理，若不在范围内，就以时间窗的最早开始时间和最晚结束时间作为EMS厂家的开始时间和deadline

    ems_n_start_time, ems_n_d_list, no_work_time_re, work_time_list, interval_time = time_window_process(time_window, ems_begin_time,
                                                                                          ems_end_time)  # 时间窗的时间可能不是连续的，我们需要将不连续的时间去掉，使其变的连续，方便时间窗的计算，就像这样[[540, 740],[740, 940],[1140, 1340]] -> [[540, 740],[740, 940],[940, 1140]]
    # 将时间向前移，在那个需要移动的时间窗范围内的时间也需要移动，在时间窗模型计算完后，再把解进行还原
    # 这个函数处理了EMS的开始时间和结束时间
    if (is_splitting_car==False):
        job_total, job_type_total, job_re_ems, goods_num_ems, ems_car_d_num, ems_car_d_type, ems_car_d_goods_num, _, _, order_sequence_ems = load_without_splitting_car(ems_goods_num,ems_job_type,ems_goods,ems_detail_add_date)   #不分车模式下的装车，假设车内的货物数量是无限的，把所有货物按照顺序加到车内
        job_se_total, job_se_type_total, zz_job_re, zz_goods_num_new, zz_car_d_num, zz_car_d_type, zz_car_d_goods_num, no_car_re, no_job_data_re,order_sequence_zz = load_without_splitting_car(zz_goods_num,zz_job_type,zz_goods,zz_detail_add_date)   #不分车模式下的装车，假设车内的货物数量是无限的，把所有货物按照顺序加到车内
    else:
        job_total, job_type_total, job_re_ems, goods_num_ems, ems_car_d_num, ems_car_d_type, ems_car_d_goods_num = load_fun_3(
            ems_goods_num, ems_job_type, len(ems_goods_num), fu_dong_EMS, rong_liang_EMS, zhuan_hua_EMS,
            ems_goods)  # EMS装车模型

        job_se_total, job_se_type_total, zz_job_re, zz_goods_num_new, zz_car_d_num, zz_car_d_type, zz_car_d_goods_num, no_car_re, no_job_data_re = load_se(
            zz_goods_num, zz_job_type, rong_liang_zz, zhuan_hua_zz, zz_goods, zz_car_num,t1,logger)  # 自制装车模型
        order_sequence_ems = []
        order_sequence_zz = []

    if (is_splitting_car==False):
        zz_begin_time,zz_end_time = update_zz_time_when_not_splitting_car(time_window, insert_time, zz_begin_time,zz_end_time)

    if insert_time !=None:
        car_time_before = insert_get_se_car_to_time_before(job_se_total, zz_begin_time, zz_end_time,
                                                           zz_car_num, insert_time)#(弃用)
    else:
        car_time_before = get_se_car_to_time_before(job_se_total, zz_begin_time, zz_end_time,
                                                    zz_car_num)  # (弃用)该函数用于得到还未经time_window_process_se函数处理过的自制发车时间，主要作用就是给排的自制车分配发车的开始时间和结束时间，然后方便get_end_zz_time函数的使用


    zz_n_start_time, zz_n_d_list = time_window_process_se(time_window, zz_begin_time,
                                                          zz_end_time)  # 时间窗的时间可能不是连续的，我们需要将不连续的时间去掉，使其变的连续，方便时间窗的计算，就像这样[[540, 740],[740, 940],[1140, 1340]] -> [[540, 740],[740, 940],[940, 1140]]
    # 将时间向前移，在那个需要移动的时间窗范围内的时间也需要移动，在时间窗模型计算完后，再把解进行还原
    # 这个函数处理了自制发车表的开始时间和结束时间
    if insert_time !=None:
        insert_time = update_insert_time(time_window, no_work_time_re, insert_time) #更新插入时间
        car_time = insert_get_se_car_to_time(job_se_total, zz_n_start_time, zz_n_d_list,
                                             zz_car_num, insert_time)#(弃用)
    else:
        car_time = get_se_car_to_time(job_se_total, zz_n_start_time, zz_n_d_list,
                                      zz_car_num)  #(弃用)该函数就是把处理后的自制发车表时间分配给排的自制车，在功能的实现上和get_se_car_to_time_before是一样的，但是得到的时间是经过time_window_process_se处理过的

    # sxt, sbsj, sbc, sbc_n = se_solve(job_se_total, job_se_type_total, zz_n_start_time, copy.deepcopy(V_se_j), s_c, a_c,
    #                                  dis, car_time,
    #                                  copy.deepcopy(V_j), t2, zz_interval_time, c, rong_liang_zz, zhuan_hua_zz,
    #                                  box_flow_value, zz_delivery_count, ems_delivery_count, zz_priority,
    #                                  max_time,random_index,random_ems_index, random_zz_index,floor_speed_map,portEmsLpnNum3,portEmsLpnNum2,portSelfLpnNum2,order_sequence_zz,is_splitting_car,floor_port_num_map,ems_floor,zz_floor,port_assignment_map,logger)  # 自制时间窗

    # solution_x_total, solution_bool_sub_job, solution_bool_C = solve(job_total, ems_n_d_list, job_type_total,
    #                                                                  ems_n_start_time,
    #                                                                  sxt, sbsj, sbc_n, job_se_type_total,
    #                                                                  copy.deepcopy(V_j), s_c, c, p_num,
    #                                                                  a_c, dis, t1, EMS_interval_time, rong_liang_EMS,
    #                                                                  zhuan_hua_EMS, box_flow_value, zz_delivery_count,
    #                                                                  ems_delivery_count, ems_priority,
    #                                                                  max_time,work_time_list, interval_time,random_index,random_ems_index,random_zz_index,portEmsLpnNum3,portEmsLpnNum2,portSelfLpnNum2,order_sequence_ems,is_splitting_car,floor_port_num_map,ems_floor,zz_floor,port_assignment_map,floor_speed_map,logger)  # EMS时间窗

    sxt, sbsj, sbc, sbc_n, solution_x_total, solution_bool_sub_job, solution_bool_C, end_sxt_ = solve_all(job_se_total, job_se_type_total, dis, t2, zz_interval_time,
                                     rong_liang_zz, zhuan_hua_zz, box_flow_value,  zz_priority, max_time,floor_speed_map,is_splitting_car,floor_port_num_map,ems_floor,zz_floor,port_assignment_map,floor_delivery_num_map,
                                     job_total, ems_n_d_list, job_type_total, ems_n_start_time,
                                     EMS_interval_time, rong_liang_EMS,zhuan_hua_EMS,
                                     ems_priority,work_time_list, interval_time,zz_n_start_time, zz_n_d_list,zz_car_num,zz_begin_time,zz_end_time,logger)

    end_solution_x_total = get_end_time(solution_x_total, solution_bool_sub_job, no_work_time_re,
                                        work_time_list)  # 更新结束时间窗时间，该函数用于得到加入不工作时间后最终的时间窗结果

    end_sxt = get_end_time(sxt, sbsj, no_work_time_re, work_time_list)  # 更新结束时间窗时间，该函数用于得到加入不工作时间后最终的时间窗结果

    zz_r = copy.deepcopy(end_sxt)  # 保存自制的真实作业时间

    # if (is_splitting_car==True):
    #     end_sxt = get_end_zz_time(car_time_before, end_sxt, sbsj)  # 该函数用于将自制的真实工作时间转换为自制的发车表时间
    if (is_splitting_car==True):
        end_sxt = copy.deepcopy(end_sxt_)

    car = job_total + job_se_total  # 得到最终的装车模型的输出（EMS在前，自制在后)

    goods_num = goods_num_ems + zz_goods_num_new  # 得到最终的货物内部数量的输出

    solution_bool_C = solution_c_ems_process(end_solution_x_total, job_total, job_type_total, solution_bool_sub_job,
                                             solution_bool_C, dis,floor_speed_map,ems_floor,floor_port_num_map)  # 通道结果更新，通道资源过多的处理

    sbc = solution_c_zz_process(zz_r, job_se_total, job_se_type_total, sbsj, sbc,
                                dis,floor_speed_map,zz_floor,floor_port_num_map)  # 通道结果更新，通道资源过多的处理

    # # 修正优先级调整后的下标
    # for i in range(len(job_re_ems)):
    #     for j in range(len(job_re_ems[i])):
    #         for k in range(len(job_re_ems[i][j])):
    #             for p in range(len(job_re_ems[i][j][k])):
    #                 job_re_ems[i][j][k][p][0] = index_original_ems[i]
    #
    # # 修正优先级调整后的下标
    # for i in range(len(zz_job_re)):
    #     for j in range(len(zz_job_re[i])):
    #         for k in range(len(zz_job_re[i][j])):
    #             for p in range(len(zz_job_re[i][j][k])):
    #                 zz_job_re[i][j][k][p][0] = index_original_zz[i]


    # 下标处理，对自制下标的处理，方便EMS和自制下标的合并
    for i in range(len(zz_job_re)):
        for j in range(len(zz_job_re[i])):
            for k in range(len(zz_job_re[i][j])):
                for p in range(len(zz_job_re[i][j][k])):
                    zz_job_re[i][j][k][p][0] += len(job_re_ems)

    # 下标处理，将自制和EMS的下标合并
    job_re = job_re_ems + zz_job_re

    # 下标处理，对下标进行最终的处理，得到输出需要的下标
    job_re_end = process_job_re(job_re)



    # 格式处理，对货物数量和货物内部数量的处理，得到客户需要的输出格式
    total_d_num, total_d_goods = d_process(job_re, job_re_end, ems_car_d_num, ems_car_d_type, ems_car_d_goods_num,
                                           zz_car_d_num, zz_car_d_type, zz_car_d_goods_num)


    #优先级处理，把排序后的优先级还原
    for i in range(len(job_re_end)):
        for j in range(len(job_re_end[i])):
            for k in range(len(job_re_end[i][j])):
                for p in range(len(job_re_end[i][j][k])):
                    if i < len(job_re_ems):
                        job_re_end[i][j][k][p][0] = index_original_ems[i]
                    else:
                        job_re_end[i][j][k][p][0] = index_original_zz[i - len(job_re_ems)] + len(job_re_ems)

    if bool(no_car_re):         # 数据拼接
        for i in range(len(no_car_re)):
            f = no_car_re[i][0]
            no_car_re[i][0] = index_original_zz[f] + len(job_re_ems)

    new_no_job_data_re = []
    new_no_car_re = []
    re_s = set()
    for i in range(len(no_car_re)):
        if tuple(no_car_re[i]) not in re_s:                                                                         #去重
            re_s.add(tuple(no_car_re[i]))
            new_no_car_re.append(copy.deepcopy(no_car_re[i]))
            new_no_job_data_re.append(copy.deepcopy(no_job_data_re[i]))
        else:
            new_no_job_data_re[new_no_car_re.index(no_car_re[i])][0] += copy.deepcopy(no_job_data_re[i][0])
            new_no_job_data_re[new_no_car_re.index(no_car_re[i])][1] += copy.deepcopy(no_job_data_re[i][1])
    end_solution_x_total, end_sxt, zz_r = repair_time(end_solution_x_total, end_sxt, zz_r, min_time)    #还原处理，把归一化的数值还原

    return end_solution_x_total, solution_bool_sub_job, solution_bool_C, end_sxt, sbsj, sbc, car, job_re_end, job_total, \
           job_type_total, job_se_total, job_se_type_total, goods_num, total_d_num, total_d_goods, zz_r, new_no_car_re, new_no_job_data_re


def get_ems_end_time(time_window,ems_end_time):
    '''
    若ems的某个厂家的结束时间为None或0时0分0秒，则将时间窗的最后一个时间间隔的结束时间作为新的结束时间
    :param time_window:工作时间窗；维度1，维度2 =  某个时间间隔，时间
    :param ems_end_time:对应于EMS厂家的最晚结束时间，只有一个维度
    :return new_ems_end_time 新的ems结束时间
    '''
    new_ems_end_time = []
    for t in ems_end_time:   #遍历结束时间
        if t == None:        #如果结束时间是None，则置为时间窗的结束时间
            new_ems_end_time.append(time_window[-1][-1])
        else:               #如果结束时间不是None，则进一步判断
            dt_object = datetime.fromtimestamp(t)
            # 提取小时、分钟和秒
            hour = dt_object.hour
            minute = dt_object.minute

            second = dt_object.second
            if hour==0 and minute ==0 and second==0:  #如果结束时间是0时0分0秒，则置为时间窗的结束时间
                new_ems_end_time.append(time_window[-1][-1])
            else:
                new_ems_end_time.append(t)

    return new_ems_end_time

def main_fun(ems_goods_num, ems_begin_time, ems_end_time,
            ems_job_type, ems_goods, zz_goods_num,
            zz_begin_time,
            zz_end_time, zz_job_type, zz_goods,
            fu_dong_EMS, fu_dong_zz,
            rong_liang_EMS, rong_liang_zz, zhuan_hua_EMS,
            zhuan_hua_zz, time_window, dis,
            zz_car_num, t1, t2, ems_i_time, zz_i_time, ems_priority, zz_priority, deliver_plan_time, detail_port_num,
            detail_id_arr, insert_time, global_time, box_flow_value,ems_detail_add_date,zz_detail_add_date,is_splitting_car,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map,logger):



    if deliver_plan_time == [] and detail_port_num == [] and detail_id_arr == [] :
        end_solution_x_total, solution_bool_sub_job, solution_bool_C, end_sxt, sbsj, sbc, car, job_re, job_total, \
        job_type_total, job_se_total, job_se_type_total, goods_num, total_d_num, total_d_goods, zz_real, no_car_re, no_job_data_re = walkthrough_fun(
            ems_goods_num, ems_begin_time, ems_end_time,
            ems_job_type, ems_goods, zz_goods_num,
            zz_begin_time,
            zz_end_time, zz_job_type, zz_goods,
            fu_dong_EMS, fu_dong_zz,
            rong_liang_EMS, rong_liang_zz, zhuan_hua_EMS,
            zhuan_hua_zz, time_window, dis,
            zz_car_num, t1, t2, ems_i_time, zz_i_time, ems_priority, zz_priority, global_time, box_flow_value,
           insert_time,ems_detail_add_date,zz_detail_add_date,is_splitting_car,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map,logger)
    else:
        end_solution_x_total, solution_bool_sub_job, solution_bool_C, end_sxt, sbsj, sbc, car, job_re, job_total, \
        job_type_total, job_se_total, job_se_type_total, goods_num, total_d_num, total_d_goods, zz_real, no_car_re,no_job_data_re = insert_fun(
            ems_goods_num, ems_begin_time, ems_end_time,
            ems_job_type, ems_goods, zz_goods_num,
            zz_begin_time,
            zz_end_time, zz_job_type, zz_goods,
            fu_dong_EMS, fu_dong_zz,
            rong_liang_EMS, rong_liang_zz, zhuan_hua_EMS,
            zhuan_hua_zz, time_window, dis,
            zz_car_num, t1, t2, ems_i_time, zz_i_time, ems_priority, zz_priority, deliver_plan_time, detail_port_num,
            detail_id_arr, insert_time, global_time, box_flow_value, ems_detail_add_date,zz_detail_add_date,is_splitting_car,ems_floor,zz_floor,floor_speed_map,floor_port_num_map,floor_delivery_num_map,port_assignment_map,logger)

    return end_solution_x_total, solution_bool_sub_job, solution_bool_C, end_sxt, sbsj, sbc, car, job_re, job_total, job_type_total, job_se_total, job_se_type_total, goods_num, total_d_num, total_d_goods, zz_real, no_car_re, no_job_data_re

if __name__ == '__main__':
    ems_goods_num = [[[[1]]], [
        [[1], [7], [1, 1], [2], [1], [1], [1], [1], [1], [1], [2], [10], [3], [5], [1], [2], [1], [1], [1], [1], [1],
         [1], [1], [1], [1], [1], [3], [1], [1], [1], [1], [1], [1], [2], [1], [1], [1], [1], [1], [1], [1], [1], [1],
         [5], [2], [1]]], [
                         [[9], [1], [2], [2], [1], [2, 1], [1, 2], [1], [1], [1, 1], [1], [1], [3], [1], [1], [1], [2],
                          [1], [4], [10], [1], [1], [2], [1], [1, 3], [2], [1], [3], [3], [3], [11], [1], [1], [1], [1],
                          [1], [4], [1], [1], [7], [1], [2, 2], [1], [1], [4, 4], [1], [1], [2]]], [
                         [[1], [1], [1], [3], [1], [6], [1], [2], [1], [3], [3], [3], [1], [1], [1], [2], [3, 2], [3],
                          [1], [1], [1], [1], [2], [2], [1], [1], [1], [1], [1], [1], [1], [2], [1, 6], [2], [9], [4],
                          [3], [1, 1], [1]]], [
                         [[2], [1], [1], [1], [1], [1], [1], [1], [3], [2], [1], [1], [1], [2], [1], [1], [1], [1], [1],
                          [1], [1], [2], [1], [1], [1], [1], [1], [1], [1]]], [[[1], [2]]], [
                         [[2], [2], [3], [1], [4], [1], [2], [5], [2], [4], [4], [5], [1], [1], [3], [1], [1, 7], [1],
                          [2], [8], [3], [3], [2], [1], [3], [2], [4], [1], [1], [1], [3], [1], [3, 1], [1], [1], [1],
                          [2], [1]]], [[[1], [3]]], [
                         [[7], [1], [7], [5], [1], [6], [2], [1], [1, 1], [2], [4], [1], [2], [6], [1], [1], [1, 1],
                          [3], [1, 1], [1], [1], [2], [1], [4], [2], [1, 1], [1], [1], [1], [1], [2, 1], [1], [1], [1],
                          [3], [1], [1], [1, 2], [3], [2], [4], [2], [1], [1], [2], [1], [2], [1], [1], [1], [3], [21],
                          [1, 1], [1], [1], [3], [1]]], [[[1]]], [[[16], [1]]], [[[1], [4]]],
                     [[[1], [1], [2], [1], [1], [2], [4], [1], [2]]], [[[1]]], [
                         [[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [2], [1], [2], [1], [1], [1], [1],
                          [1], [1]]],
                     [[[1], [8], [4], [2], [1], [1], [1], [2], [1], [1], [1], [2], [1], [1], [2], [1], [1], [5]]],
                     [[[2], [1], [2], [1], [8]]],
                     [[[5], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [2], [1], [4], [1], [2], [1]]],
                     [[[1]]], [[[2]]], [[[1], [1, 1], [1], [1, 3]]],
                     [[[1], [2], [6], [2], [2], [14], [1], [1], [4], [1, 1]]], [[[1], [1], [1], [5]]],
                     [[[1], [1], [3], [1], [4]]], [[[1]]], [
                         [[2], [1], [1], [17], [2], [4], [3], [1], [2], [1], [1], [1], [1], [1], [1], [2], [1], [1],
                          [7], [1], [1, 10], [1], [4]]], [[[2], [1], [1], [1, 1], [1], [1], [2]]], [[[1]]], [[[1]]],
                     [[[1], [1], [4], [2]]], [[[1], [1]]], [[[1], [1]]], [
                         [[1], [1], [1], [1], [1], [1], [5], [1], [1], [1], [1], [1], [4], [1], [4], [1], [1], [2], [1],
                          [4], [6], [1], [1], [2]]], [[[1], [1], [1]]], [[[1]]], [
                         [[1], [1], [2], [1], [1], [1], [1], [1], [1], [2], [1], [1], [2], [1], [1], [1], [1, 5], [1],
                          [1], [1]]], [[[1], [1], [1], [1]]], [[[2], [1], [4], [2], [1], [1], [1]]],
                     [[[1], [3], [1], [1], [1], [1], [1], [1], [3], [4], [1], [1], [1], [30], [4], [1]]], [
                         [[1], [1], [1], [1], [1], [4], [1], [1], [1], [1], [2], [1], [1], [1], [1], [1], [1], [1], [1],
                          [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [8], [2], [1], [1], [1], [1], [5], [1], [2],
                          [1]]], [[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]], [[[1]]],
                     [[[7], [1, 22], [1, 82], [14], [2], [1], [35], [1], [7], [1], [3, 1]]],
                     [[[1], [1], [10], [1], [3, 2], [1]]], [[[1], [1, 3]]], [[[2], [1], [1], [1], [1]]],
                     [[[1], [1], [1], [1], [1], [8]]], [[[1]]], [[[3]]],
                     [[[1], [5], [4], [1], [1], [1, 1], [1], [1], [1], [2], [1, 3], [5, 3], [6, 1], [1]]],
                     [[[1], [1], [1], [1], [1], [1], [5], [11]]], [[[5], [3], [1], [1, 4], [1], [2], [4], [5]]],
                     [[[20], [3]]], [[[1], [2], [1], [1]]], [[[1]]], [[[1]]], [[[6]]], [[[1], [1]]], [[[1]]], [[[1]]],
                     [[[8]]], [[[1]]], [[[17], [1]]], [[[2], [1], [1, 5], [2], [4]]], [[[1]]], [[[2]]], [[[1], [1]]],
                     [[[1], [1], [1]]], [[[2], [8], [2], [1]]], [[[1]]], [[[1], [2], [2], [1]]], [[[1]]],
                     [[[1], [4], [1], [3], [1, 2], [1], [11]]], [[[8], [8]]]]
    zz_goods_num = [
        [[[2], [2], [2], [1], [1], [1], [2], [1], [3], [3], [1], [3], [1], [1], [1], [1], [1], [2], [3], [1]]],
        [[[1], [2], [2], [2], [1], [1], [1], [1], [1]]], [
            [[1], [2], [1, 5], [1], [13], [1], [3], [1, 2], [2], [1], [1], [1], [1], [17], [1], [1], [1], [1], [1], [2],
             [1], [2], [2], [1], [1, 3], [1]]], [
            [[1], [1, 3], [4], [1], [4], [1], [2], [1], [1], [1], [1], [1], [1], [1], [1], [1], [10], [2], [1], [2],
             [35], [1], [1], [1], [1, 9], [5], [1], [5, 7], [1], [1], [1], [2], [5], [1], [1], [8], [1], [2], [1], [2],
             [1], [1], [1], [1], [2], [2], [13], [2], [2], [4], [1], [3], [5], [1], [1], [2], [1], [1], [1], [6, 3],
             [1], [1], [1], [1], [1], [5], [1]]], [
            [[2], [1], [1], [2], [1], [1], [1], [1], [2], [1], [2], [3], [1, 1], [1], [2], [1], [1], [1], [1], [1], [1],
             [1]]], [
            [[1], [1], [1], [2, 1], [1], [3], [1, 2], [3], [1], [9], [1, 1], [2], [1], [1], [1], [9], [1], [1], [1],
             [3], [1], [2]]], [[[1], [1], [1], [1], [2], [1], [8], [2], [1], [1], [2], [3], [3], [1]]],
        [[[2], [2], [1], [11], [1], [1]]], [[[2], [1], [1], [3], [1], [1], [1], [1], [1], [2]]],
        [[[1, 5], [1], [2], [1], [1], [3], [1]]], [[[1], [1], [2], [5], [2], [2]]], [[[5], [1], [1], [1], [1]]],
        [[[1], [1], [8], [2]]], [
            [[1], [2], [1], [10], [1], [1], [1, 1], [1], [1], [1], [1], [1], [1], [2], [1], [10], [1], [1], [5], [2],
             [1], [1], [1], [1], [2], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1, 1], [1], [1], [1], [1], [1], [1],
             [3], [1], [1]]], [[[4], [1], [1], [1], [1], [2]]], [
            [[2], [1], [1], [2], [4], [1], [1], [1], [1, 9], [3], [1], [1], [2], [19], [1], [2], [2], [2], [17], [1],
             [1], [1], [3], [1], [1], [1], [3], [1], [3], [6], [4], [1]]], [[[1], [1], [1], [1], [1], [1], [1]]],
        [[[1], [2], [1], [1], [1], [1], [5], [2], [1]]], [[[1], [17], [1], [1], [1], [1], [1]]],
        [[[1], [1], [1], [1], [2], [1], [1], [1], [1]]], [[[1], [1], [1], [1]]], [[[1], [1], [1], [1], [1], [1]]],
        [[[3], [1, 3], [4], [1], [1, 4]]], [[[1], [1], [1]]],
        [[[1], [1, 3], [8], [1], [3], [1], [1], [1], [1], [2], [1], [3], [8], [1], [1], [2], [1], [1], [1], [2], [2]]],
        [[[1], [1]]], [[[5], [6]]], [[[1]]], [[[3], [4], [1]]], [[[2], [1], [2]]], [[[1], [1], [1], [8], [1, 13], [2]]],
        [[[1], [4], [1], [1], [1], [3], [1], [1], [4], [1], [2], [3], [1], [1], [1], [1], [3], [1], [3], [1]]], [[[1]]],
        [[[3], [1], [3], [1], [1]]], [[[1], [1], [4], [1], [3], [1], [1], [1], [2]]],
        [[[1], [2], [2], [1], [2], [1], [1], [1], [1], [2], [2], [1]]], [[[1], [1]]], [[[1]]], [[[1], [1]]]]
    ems_job_type = [[[[1]]], [
        [[1], [0], [0, 1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [1], [1], [1], [1],
         [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [1], [1], [1], [1],
         [1], [1], [1]]], [
                        [[0], [1], [1], [1], [1], [0, 1], [0, 1], [1], [1], [0, 1], [1], [0], [1], [1], [0], [0], [1],
                         [1], [1], [1], [0], [1], [1], [0], [0, 1], [0], [1], [0], [1], [0], [1], [1], [1], [1], [0],
                         [1], [1], [0], [1], [1], [1], [0, 1], [1], [1], [0, 1], [1], [1], [1]]], [
                        [[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0, 1], [1],
                         [1], [1], [0], [1], [1], [1], [1], [1], [1], [0], [1], [0], [1], [1], [0, 1], [1], [1], [1],
                         [1], [0, 1], [1]]], [
                        [[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1],
                         [1], [1], [1], [1], [1], [1], [0], [1], [1], [1]]], [[[0], [1]]], [
                        [[0], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0, 1], [1],
                         [1], [1], [1], [1], [1], [1], [0], [0], [1], [1], [1], [1], [1], [1], [0, 1], [1], [1], [1],
                         [1], [1]]], [[[1], [1]]], [
                        [[1], [1], [1], [1], [0], [1], [1], [1], [0, 1], [1], [1], [0], [1], [1], [1], [1], [0, 1], [1],
                         [0, 1], [1], [0], [1], [1], [1], [1], [0, 1], [1], [0], [1], [1], [0, 1], [1], [1], [1], [1],
                         [1], [1], [0, 1], [1], [1], [1], [1], [1], [0], [1], [0], [1], [1], [1], [1], [1], [1], [0, 1],
                         [1], [1], [1], [1]]], [[[0]]], [[[1], [1]]], [[[1], [1]]],
                    [[[1], [1], [1], [1], [1], [1], [1], [1], [1]]], [[[1]]], [
                        [[0], [1], [1], [1], [1], [1], [0], [1], [1], [0], [1], [1], [1], [1], [1], [1], [0], [0], [1],
                         [1], [1]]],
                    [[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]],
                    [[[1], [1], [1], [1], [1]]],
                    [[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]],
                    [[[1]]], [[[1]]], [[[0], [0, 1], [1], [0, 1]]],
                    [[[1], [1], [1], [1], [1], [1], [1], [1], [1], [0, 1]]], [[[1], [1], [1], [1]]],
                    [[[1], [0], [1], [0], [1]]], [[[1]]], [
                        [[0], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [0], [1], [1], [1], [0], [1],
                         [1], [0, 1], [1], [1]]], [[[0], [1], [0], [0, 1], [1], [1], [1]]], [[[1]]], [[[1]]],
                    [[[1], [1], [1], [1]]], [[[1], [0]]], [[[1], [1]]], [
                        [[1], [1], [0], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [0], [1], [1], [1], [1], [0],
                         [1], [1], [1], [1], [1]]], [[[1], [1], [1]]], [[[1]]], [
                        [[0], [1], [0], [1], [0], [1], [0], [1], [1], [0], [0], [1], [1], [1], [1], [1], [0, 1], [1],
                         [0], [0]]], [[[1], [1], [1], [1]]], [[[1], [1], [1], [1], [0], [1], [1]]],
                    [[[1], [1], [1], [0], [1], [0], [1], [0], [1], [1], [0], [1], [0], [1], [1], [1]]], [
                        [[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [0], [1], [0],
                         [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [1],
                         [1]]], [[[1], [1], [0], [0], [0], [1], [1], [1], [1], [1]]], [[[1]]],
                    [[[1], [0, 1], [0, 1], [1], [1], [0], [1], [1], [1], [1], [0, 1]]],
                    [[[1], [1], [1], [1], [0, 1], [1]]], [[[1], [0, 1]]], [[[1], [1], [0], [1], [1]]],
                    [[[1], [1], [1], [1], [0], [1]]], [[[1]]], [[[0]]],
                    [[[1], [1], [1], [1], [0], [0, 1], [0], [0], [0], [1], [0, 1], [0, 1], [0, 1], [0]]],
                    [[[1], [1], [1], [1], [1], [1], [1], [1]]], [[[1], [1], [1], [0, 1], [0], [0], [1], [1]]],
                    [[[1], [1]]], [[[1], [1], [1], [1]]], [[[1]]], [[[0]]], [[[1]]], [[[0], [1]]], [[[0]]], [[[0]]],
                    [[[1]]], [[[1]]], [[[1], [1]]], [[[1], [1], [0, 1], [1], [1]]], [[[1]]], [[[1]]], [[[1], [1]]],
                    [[[0], [1], [1]]], [[[1], [1], [1], [0]]], [[[1]]], [[[1], [1], [1], [1]]], [[[1]]],
                    [[[1], [1], [1], [1], [0, 1], [1], [1]]], [[[1], [1]]]]
    zz_job_type = [
        [[[1], [1], [1], [1], [0], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0]]],
        [[[1], [1], [1], [1], [1], [1], [1], [1], [0]]], [
            [[0], [0], [0, 1], [1], [1], [1], [1], [0, 1], [1], [1], [0], [1], [1], [1], [1], [0], [1], [0], [1], [0],
             [1], [1], [1], [0], [0, 1], [1]]], [
            [[0], [0, 1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [1],
             [0], [1], [0], [0, 1], [1], [1], [0, 1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [1], [1],
             [1], [1], [1], [1], [0], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1], [1], [0, 1], [1], [1],
             [0], [0], [1], [1], [1]]], [
            [[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [0, 1], [1], [1], [1], [1], [0], [1], [1], [1],
             [1]]], [
            [[1], [0], [1], [0, 1], [0], [1], [0, 1], [1], [1], [1], [0, 1], [1], [1], [0], [1], [1], [1], [1], [1],
             [1], [0], [1]]], [[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]],
        [[[1], [1], [1], [1], [1], [1]]], [[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]],
        [[[0, 1], [1], [1], [1], [1], [1], [1]]], [[[1], [1], [1], [1], [1], [1]]], [[[1], [1], [1], [1], [1]]],
        [[[1], [1], [1], [1]]], [
            [[1], [1], [1], [1], [1], [1], [0, 1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1],
             [0], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [0, 1], [1], [1], [1], [1], [1], [1], [1],
             [1], [1]]], [[[1], [1], [1], [1], [1], [1]]], [
            [[0], [1], [1], [1], [1], [1], [1], [1], [0, 1], [1], [1], [1], [1], [1], [1], [0], [1], [0], [1], [0], [0],
             [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]], [[[1], [1], [1], [1], [1], [1], [1]]],
        [[[1], [1], [1], [1], [1], [1], [1], [1], [1]]], [[[1], [1], [1], [1], [1], [1], [0]]],
        [[[1], [1], [1], [1], [1], [1], [1], [1], [1]]], [[[1], [1], [1], [1]]], [[[1], [1], [1], [1], [1], [1]]],
        [[[1], [0, 1], [1], [1], [0, 1]]], [[[1], [1], [0]]],
        [[[1], [0, 1], [1], [0], [1], [1], [0], [1], [0], [1], [1], [1], [1], [0], [1], [1], [1], [1], [1], [1], [1]]],
        [[[1], [1]]], [[[0], [1]]], [[[1]]], [[[1], [1], [1]]], [[[1], [1], [1]]], [[[1], [1], [0], [1], [0, 1], [1]]],
        [[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]], [[[0]]],
        [[[1], [0], [1], [1], [0]]], [[[1], [1], [1], [1], [1], [1], [1], [1], [1]]],
        [[[1], [1], [1], [1], [1], [1], [1], [1], [1], [0], [1], [1]]], [[[1], [1]]], [[[1]]], [[[1], [1]]]]
    cl_pallet_list = [0.2, 0.2, 0.2, 0.2, 0.2, 0.1, 0.8, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.08, 0.2, 0.2, 0.2, 0.0, 0.2,
                      0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.0, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2,
                      0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.5, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2,
                      0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2]
    vehicle_pallet_list = [480, 860, 480, 20, 480, 60, 40, 360, 480, 480, 480, 360, 360, 60, 360, 360, 480, 360, 360,
                           360, 360, 480, 360, 360, 360, 360, 480, 360, 480, 360, 480, 360, 480, 480, 480, 480, 360,
                           480, 780, 480, 480, 760, 760, 760, 480, 360, 480, 480, 360, 480, 20, 360, 480, 360, 480, 360,
                           480, 480, 480, 480, 360, 480, 360, 360, 360, 360, 780, 360, 360, 480, 480, 360, 480, 360]
    pallet_to_case_list = [20, 20, 20, 5, 20, 6, 4, 20, 20, 20, 20, 20, 20, 6, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
                           20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
                           20, 20, 20, 5, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
                           20, 20, 20, 20]
    zz_cl_pallet_list = [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2,
                         0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.0, 0.2, 0.2,
                         0.2]
    zz_vehicle_pallet_list = [360, 400, 400, 360, 360, 360, 360, 360, 360, 360, 400, 360, 360, 360, 360, 400, 400, 360,
                              360, 400, 400, 400, 480, 360, 360, 360, 360, 360, 360, 360, 400, 360, 360, 360, 360, 480,
                              360, 360, 360]
    zz_pallet_to_case_list = [20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
                              20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20]
    ems_pcs_num = [[[[85000.0]]], [
        [[1650.0], [2400.0, 2400.0, 2400.0, 2400.0, 2400.0, 2400.0, 2320.0], [496000.0, 16000.0], [20000.0, 11000.0],
         [19200.0], [11000.0], [30000.0], [180000.0], [615000.0], [580000.0], [2000.0, 22000.0],
         [250.0, 250.0, 250.0, 250.0, 250.0, 250.0, 250.0, 250.0, 250.0, 250.0], [15000.0, 240000.0, 375000.0],
         [500.0, 500.0, 500.0, 500.0, 500.0], [10800000.0], [3900.0, 10400.0], [3840.0], [6300.0], [81000.0],
         [330000.0], [5200.0], [84000.0], [17000.0], [4080.0], [400000.0], [4800.0], [1200.0, 1200.0, 1200.0],
         [16000.0], [10500.0], [70000.0], [4000.0], [49975.0], [1039930.0], [2300.0, 8400.0], [3990.0], [10000.0],
         [54432.0], [3000.0], [6400.0], [4000.0], [18000.0], [60000.0], [1500.0], [320.0, 320.0, 320.0, 320.0, 320.0],
         [300.0, 5700.0], [53961.0]]], [
                       [[1440.0, 1440.0, 1440.0, 1440.0, 1440.0, 1440.0, 1440.0, 1440.0, 1440.0], [2000.0],
                        [4200.0, 4200.0], [532.0, 529.0], [4800.0], [6750.0, 6750.0, 600.0], [7000.0, 1000.0, 900.0],
                        [2800.0], [14600.0], [1200.0, 120.0], [2800.0], [14400.0], [1600.0, 280.0, 1600.0], [120000.0],
                        [19200.0], [80000.0], [810.0, 810.0], [4000.0], [4000.0, 4000.0, 4000.0, 4000.0],
                        [200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0], [1200.0], [150.0],
                        [1600.0, 1300.0], [20280000.0], [1600.0, 800.0, 800.0, 800.0], [12630.0, 4700.0], [4000.0],
                        [1650.0, 1800.0, 1800.0], [1200.0, 1200.0, 1200.0], [6400.0, 6400.0, 6400.0],
                        [200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0], [3600.0],
                        [4800.0], [800.0], [1200.0], [400.0], [600.0, 600.0, 600.0, 600.0], [28800.0], [2000.0],
                        [200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0], [23000.0], [450.0, 975.0, 75.0, 75.0],
                        [3000.0], [42000.0], [1200.0, 2400.0, 2400.0, 2400.0, 200.0, 200.0, 188.0, 171.0], [3600.0],
                        [103975.0], [800.0, 800.0]]], [
                       [[3000.0], [8250.0], [84925.0], [1350.0, 1350.0, 1350.0], [15000.0],
                        [450.0, 675.0, 675.0, 675.0, 225.0, 675.0], [300.0], [9000.0, 90000.0], [39995.0],
                        [1800.0, 1800.0, 1800.0], [1800.0, 1194.0, 1800.0], [5500.0, 5500.0, 5500.0], [44925.0],
                        [4789.0], [3150.0], [600.0, 150.0], [750.0, 750.0, 2850.0, 300.0, 300.0],
                        [1152.0, 1152.0, 1152.0], [180000.0], [650000.0], [3780.0], [104900.0], [9000.0, 39000.0],
                        [1386.0, 1386.0], [15000.0], [15000.0], [900000.0], [6000.0], [40000.0], [7980.0], [3000.0],
                        [2352.0, 25872.0], [91000.0, 1500.0, 2000.0, 2000.0, 2000.0, 2000.0, 4000.0],
                        [110000.0, 190000.0], [320.0, 320.0, 320.0, 320.0, 320.0, 320.0, 320.0, 320.0, 320.0],
                        [2744.0, 2744.0, 4.0, 3000.0], [1170.0, 1170.0, 1170.0], [5040.0, 1008.0], [240000.0]]], [
                       [[2963.0, 51000.0], [495000.0], [10000.0], [81000.0], [9000.0], [539945.0], [180000.0], [7500.0],
                        [60000.0, 40000.0, 1140000.0], [2000.0, 2000.0], [30000.0], [30000.0], [90000.0],
                        [6000.0, 48000.0], [900000.0], [81000.0], [1800000.0], [48000.0], [180000.0], [240000.0],
                        [16000.0], [10000.0, 90000.0], [7470.0], [14400.0], [14400.0], [5952000.0], [600000.0],
                        [105000.0], [180000.0]]], [[[41998.0], [50000.0, 25000.0]]], [
                       [[5385000.0, 13575000.0], [8000.0, 92000.0], [45000.0, 45000.0, 30000.0], [70000.0],
                        [70000.0, 270000.0, 180000.0, 70000.0], [600000.0], [4000.0, 5000.0],
                        [12000.0, 12000.0, 2600.0, 2726.0, 2244.0], [96000.0, 80000.0],
                        [180000.0, 180000.0, 90000.0, 90000.0], [50000.0, 30000.0, 10000.0, 10000.0],
                        [90000.0, 100000.0, 40000.0, 29945.0, 120000.0], [140000.0], [2400.0],
                        [15000.0, 12000.0, 3000.0], [160000.0],
                        [1880.0, 144.0, 64.0, 320.0, 320.0, 320.0, 320.0, 320.0], [240000.0], [15000.0, 550000.0],
                        [87000.0, 21000.0, 63000.0, 17975.0, 90000.0, 24000.0, 63000.0, 63000.0],
                        [195000.0, 195000.0, 75000.0], [30000.0, 900000.0, 600000.0], [300000.0, 299900.0], [90000.0],
                        [37500.0, 1369.0, 202380.0], [28200000.0, 4500000.0], [100000.0, 240000.0, 260000.0, 160000.0],
                        [120000.0], [200000.0], [499800.0], [30000.0, 30000.0, 60000.0], [400000.0],
                        [16212.0, 43987.0, 35208.0, 2500.0], [1500.0], [22400.0], [28994.0], [3000.0, 111000.0],
                        [45000.0]]], [[[2560.0], [3000.0, 4000.0, 4000.0]]], [
                       [[10000.0, 599930.0, 490000.0, 470000.0, 600000.0, 600000.0, 400000.0], [27955.0],
                        [200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0], [1000.0, 1000.0, 1000.0, 1000.0, 1000.0],
                        [1600.0], [200000.0, 200000.0, 200000.0, 200000.0, 200000.0, 80000.0], [1640.0, 8000.0],
                        [6400.0], [9120.0, 3040.0], [75000.0, 195000.0], [30000.0, 150000.0, 130000.0, 250000.0],
                        [3200.0], [1520.0, 3040.0], [800.0, 800.0, 800.0, 800.0, 800.0, 800.0], [1800.0], [850.0],
                        [528000.0, 1000.0], [350000.0, 490000.0, 750000.0], [1960000.0, 180000.0], [1600.0], [21000.0],
                        [3894.0, 6500.0], [15000.0], [350000.0, 140000.0, 700000.0, 560000.0], [3600.0, 18000.0],
                        [6000.0, 500.0], [1500000.0], [3300.0], [4000.0], [81000.0], [2119.0, 10890.0, 2654.0],
                        [340000.0], [225000.0], [5000.0], [450.0, 450.0, 450.0], [3000.0], [45000.0],
                        [128450.0, 3000.0, 21000.0], [1250000.0, 1250000.0, 765000.0], [8000.0, 8000.0],
                        [276000.0, 240000.0, 240000.0, 240000.0], [10000.0, 72000.0], [21168.0], [113998.0],
                        [840.0, 3360.0], [69000.0], [700.0, 700.0], [12800.0], [570000.0], [50000.0],
                        [45000.0, 60000.0, 60000.0],
                        [4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0,
                         4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0, 4800.0], [17600.0, 400.0],
                        [350000.0], [555000.0], [650.0, 2600.0, 2600.0], [255.0]]], [[[19500.0]]], [[[578.0, 566.0,
                                                                                                      558.0, 549.0,
                                                                                                      545.0, 544.0,
                                                                                                      567.0, 560.0,
                                                                                                      574.0, 559.0,
                                                                                                      547.0, 432.0,
                                                                                                      394.0, 579.0,
                                                                                                      580.0, 271.0],
                                                                                                     [3600.0]]],
                   [[[3600.0], [900000.0, 795000.0, 10000.0, 950000.0]]], [
                       [[120000.0], [49500.0], [600000.0, 450000.0], [38400.0], [809990.0], [9254.0, 370000.0],
                        [7500.0, 7500.0, 7500.0, 7500.0], [12000.0], [15000.0, 675000.0]]], [[[40000.0]]], [
                       [[18045000.0], [30000.0], [72000.0], [90000.0], [765000.0], [81000.0], [1950000.0], [208000.0],
                        [160000.0], [23910000.0], [3200.0], [900000.0], [40000.0, 70000.0], [240000.0],
                        [1000.0, 1000.0], [1400.0], [13390000.0], [7680000.0], [20000.0], [3600.0], [81000.0]]], [
                       [[3600.0], [120.0, 120.0, 120.0, 120.0, 120.0, 120.0, 120.0, 120.0],
                        [780.0, 780.0, 780.0, 780.0], [2800.0, 2800.0], [200000.0], [360.0], [4500.0], [1800.0, 1800.0],
                        [4800.0], [4800.0], [4000.0], [400.0, 400.0], [6400.0], [120.0], [3965.0, 3125.0], [1800.0],
                        [12000.0], [600.0, 600.0, 600.0, 600.0, 600.0]]], [
                       [[12000.0, 4000.0], [400000.0], [6000.0, 6000.0], [600000.0],
                        [2760.0, 2760.0, 2760.0, 2760.0, 2760.0, 2760.0, 2760.0, 2560.0]]], [
                       [[280.0, 139.0, 56.0, 157.0, 91.0], [27000.0], [3000.0], [1920.0], [1500.0], [235000.0], [672.0],
                        [4200.0], [1272.0], [2600.0], [2000.0], [240000.0], [800.0, 6400.0], [3600.0],
                        [60.0, 60.0, 60.0, 60.0], [1920.0], [2760.0, 2560.0], [3500.0]]], [[[8000.0]]],
                   [[[50000.0, 50000.0]]], [[[4500.0], [10000.0, 1200.0], [10000.0], [852.0, 640.0, 640.0, 480.0]]], [
                       [[600.0], [5760.0, 5760.0], [1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0], [81000.0, 81000.0],
                        [5500.0, 5500.0],
                        [100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0,
                         100.0], [15000.0], [60000.0], [4800.0, 4800.0, 1440.0, 4800.0], [8250.0, 750.0]]],
                   [[[4480.0], [30000.0], [12600.0], [1320.0, 1320.0, 1320.0, 1320.0, 1320.0]]], [
                       [[8000.0], [56700.0], [144000.0, 144000.0, 144000.0], [49210.0],
                        [81000.0, 81000.0, 81000.0, 81000.0]]], [[[180000.0]]], [[[240.0, 587.0], [8000.0], [100000.0],
                                                                                  [120.0, 120.0, 120.0, 120.0, 120.0,
                                                                                   120.0, 120.0, 120.0, 120.0, 120.0,
                                                                                   120.0, 120.0, 120.0, 120.0, 120.0,
                                                                                   120.0, 120.0], [840.0, 840.0],
                                                                                  [400.0, 400.0, 400.0, 400.0],
                                                                                  [750.0, 750.0, 750.0], [2400.0],
                                                                                  [1000.0, 15000.0], [1050.0],
                                                                                  [10000.0], [4950.0], [1600.0],
                                                                                  [1400.0], [4400.0], [600.0, 5000.0],
                                                                                  [4500.0], [1344.0],
                                                                                  [300.0, 300.0, 300.0, 300.0, 300.0,
                                                                                   300.0, 300.0], [2080.0],
                                                                                  [772.0, 112.0, 112.0, 112.0, 112.0,
                                                                                   112.0, 112.0, 112.0, 112.0, 112.0,
                                                                                   112.0], [3600.0],
                                                                                  [600.0, 600.0, 600.0, 600.0]]],
                   [[[3200.0, 2700.0], [1999.0], [1920.0], [3900.0, 670.0], [1000.0], [510.0], [107.0, 2998.0]]],
                   [[[72000.0]]], [[[90000.0]]],
                   [[[1200000.0], [4800.0], [208000.0, 160000.0, 56000.0, 304000.0], [4800.0, 4800.0]]],
                   [[[5990.0], [960.0]]], [[[150000.0], [240000.0]]], [
                       [[15000.0], [236000.0], [1872000.0], [585000.0], [735000.0], [3200.0],
                        [104.0, 104.0, 104.0, 104.0, 60.0], [380000.0], [600000.0], [270000.0], [21210000.0], [40.0],
                        [375.0, 375.0, 375.0, 375.0], [25000.0], [3000.0, 3000.0, 1200.0, 3000.0], [540000.0],
                        [70000.0], [2760.0, 2560.0], [8700000.0], [600.0, 299.0, 10.0, 12.0],
                        [240.0, 240.0, 240.0, 240.0, 240.0, 240.0], [510000.0], [840000.0], [6400.0, 4000.0]]],
                   [[[420000.0], [78000.0], [90000.0]]], [[[10000.0]]], [
                       [[1011000.0], [236000.0], [729.0, 150000.0], [855000.0], [18000000.0], [800000.0], [1725000.0],
                        [180000.0], [500000.0], [6400.0, 6400.0], [5048000.0], [600000.0], [2000.0, 10000.0],
                        [102000.0], [1170000.0], [270000.0], [5400.0, 440.0, 440.0, 40.0, 600.0, 440.0], [1000000.0],
                        [10000000.0], [20850000.0]]], [[[108000.0], [170000.0], [105000.0], [66000.0]]], [
                       [[1600.0, 1600.0], [3500.0], [450.0, 450.0, 450.0, 450.0], [6000.0, 5000.0], [6400.0], [1600.0],
                        [2400.0]]], [
                       [[570000.0], [60.0, 60.0, 60.0], [900000.0], [7410000.0], [6000.0], [5084000.0], [280000.0],
                        [2940000.0], [308.0, 154.0, 154.0], [60.0, 60.0, 60.0, 60.0], [6400000.0], [400000.0],
                        [5175000.0],
                        [60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0,
                         60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0, 60.0],
                        [16.0, 16.0, 16.0, 16.0], [450000.0]]], [
                       [[900000.0], [750000.0], [590000.0], [60000.0], [232000.0], [195.0, 195.0, 195.0, 195.0],
                        [570000.0], [105000.0], [290000.0], [350000.0], [105000.0, 900000.0], [8000.0], [240000.0],
                        [27600000.0], [95950.0], [290000.0], [6480000.0], [1000000.0], [17200000.0], [405000.0],
                        [405000.0], [90000.0], [1050000.0], [525000.0], [400000.0], [1250000.0], [42000.0], [494000.0],
                        [120000.0], [18000.0, 18000.0, 18000.0, 18000.0, 18000.0, 18000.0, 11975.0, 8000.0],
                        [50000.0, 700000.0], [30000.0], [195000.0], [70000.0], [12800000.0],
                        [4800.0, 4800.0, 4800.0, 4800.0, 4800.0], [30000.0], [30000.0, 410000.0], [30000.0]]], [
                       [[600000.0], [870000.0], [2505000.0], [4644000.0], [6400000.0], [18000.0], [360000.0],
                        [280000.0], [420000.0], [60000.0]]], [[[580.0]]], [
                       [[400.0, 400.0, 400.0, 400.0, 400.0, 400.0, 400.0],
                        [5752.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0,
                         216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 216.0, 204.0],
                        [390.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0,
                         78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0,
                         78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0,
                         78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0,
                         78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0, 78.0,
                         78.0, 78.0, 78.0, 78.0],
                        [40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0],
                        [78.0, 78.0], [4000.0],
                        [240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0,
                         240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0,
                         240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0, 240.0], [120.0],
                        [400.0, 400.0, 400.0, 400.0, 400.0, 400.0, 400.0], [4000.0], [1160.0, 1280.0, 800.0, 40.0]]], [
                       [[1250000.0], [255000.0], [580.0, 580.0, 580.0, 580.0, 580.0, 580.0, 580.0, 580.0, 580.0, 580.0],
                        [1160.0], [3840.0, 4716.0, 61440.0, 5120.0, 383.0], [1388.0]]],
                   [[[45000.0], [51000.0, 3000.0, 600.0, 3000.0]]],
                   [[[300000.0, 430000.0], [900000.0], [1680000.0], [900000.0], [70000.0]]], [
                       [[240000.0], [6400.0], [900000.0], [600000.0], [21000.0],
                        [390.0, 105.0, 4000.0, 4000.0, 4000.0, 4000.0, 4000.0, 4000.0]]], [[[2560.0]]],
                   [[[4683.0, 7457.0, 13886.0]]], [
                       [[39000.0], [250.0, 250.0, 250.0, 250.0, 250.0], [33000.0, 18000.0, 44000.0, 45000.0], [5000.0],
                        [31200.0], [12225.0, 840.0], [28000.0], [80000.0], [6000.0], [5000.0, 3000.0],
                        [2400.0, 200.0, 200.0, 199.0], [1600.0, 1000.0, 64.0, 3400.0, 11000.0, 600.0, 600.0, 393.0],
                        [29700.0, 9046.0, 39600.0, 14850.0, 900.0, 24300.0, 450.0], [15200.0]]], [
                       [[600000.0], [240000.0], [50000.0], [310000.0], [24000.0], [310000.0],
                        [180.0, 180.0, 180.0, 180.0, 180.0],
                        [480.0, 480.0, 480.0, 480.0, 480.0, 480.0, 480.0, 480.0, 480.0, 480.0, 480.0]]], [
                       [[175.0, 175.0, 175.0, 175.0, 175.0], [24000.0, 80000.0, 80000.0], [2000.0],
                        [22000.0, 4000.0, 4000.0, 4000.0, 2000.0], [12000.0], [6400.0, 3600.0],
                        [4500.0, 4500.0, 4500.0, 4500.0], [4500.0, 4500.0, 4500.0, 4500.0, 4500.0]]], [[[480.0, 480.0,
                                                                                                         480.0, 480.0,
                                                                                                         480.0, 480.0,
                                                                                                         480.0, 480.0,
                                                                                                         480.0, 480.0,
                                                                                                         480.0, 480.0,
                                                                                                         480.0, 480.0,
                                                                                                         480.0, 480.0,
                                                                                                         480.0, 480.0,
                                                                                                         480.0, 480.0],
                                                                                                        [15000.0,
                                                                                                         5000.0,
                                                                                                         50000.0]]],
                   [[[600000.0], [116000.0, 160000.0], [66000.0], [900000.0]]], [[[29800.0]]], [[[1440.0]]],
                   [[[6000.0, 6000.0, 3600.0, 12000.0, 12000.0, 11991.0]]], [[[6750.0], [54000.0]]], [[[102395.0]]],
                   [[[2700.0]]], [[[3998.0, 10000.0, 4000.0, 2000.0, 10000.0, 10000.0, 10000.0, 1998.0]]],
                   [[[100000.0]]], [[[1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 296.0,
                                      36.0, 36.0, 36.0, 36.0, 36.0, 36.0, 996.0], [7680.0]]], [
                       [[2560.0, 2560.0], [2000.0], [7200.0, 600.0, 600.0, 600.0, 600.0, 600.0], [1020.0, 1020.0],
                        [600.0, 600.0, 600.0, 600.0]]], [[[250000.0]]], [[[6300.0, 6300.0]]], [[[210000.0], [27000.0]]],
                   [[[1350.0], [600.0], [2800.0]]], [
                       [[4000.0, 4000.0], [800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 400.0], [800.0, 800.0],
                        [6400.0]]], [[[900000.0]]], [[[480.0], [960.0, 960.0], [1320.0, 1320.0], [300000.0]]],
                   [[[80000.0]]], [
                       [[3000.0], [147.0, 84.0, 28.0, 42.0], [81000.0], [320.0, 320.0, 320.0], [6300.0, 9600.0, 9600.0],
                        [1260.0],
                        [1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0]]], [
                       [[2000.0, 2000.0, 2000.0, 2000.0, 2000.0, 2000.0, 2000.0, 2000.0],
                        [1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0, 1920.0]]]]
    ems_begin_time = [1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                      1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                      1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                      1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                      1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                      1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                      1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                      1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                      1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                      1734418355, 1734418355]
    ems_end_time = [1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, None, 1734448859.0,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, None,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734364800.0, 1734451199.0, 1734451199.0, 1734451199.0,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734364800.0, 1734451199.0, 1734451199.0,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                    1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0]
    zz_begin_time = [1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                     1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                     1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                     1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355,
                     1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355, 1734418355]
    zz_end_time = [1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                   1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                   1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                   1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                   1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0,
                   1734451199.0, 1734451199.0, 1734451199.0, 1734451199.0]
    zz_pcs_num = [[[[1847.0, 6000.0], [1200.0, 9600.0], [1600.0, 1600.0], [99000.0], [4956000.0], [42000.0],
                    [236000.0, 188000.0], [7200.0], [30000.0, 30000.0, 27000.0], [6000.0, 1000.0, 6000.0], [2000.0],
                    [64000.0, 64000.0, 72000.0], [3000.0], [25000.0], [10000.0], [3000.0], [25000.0], [6400.0, 4800.0],
                    [400000.0, 400000.0, 400000.0], [16215000.0]]], [
                      [[2000.0], [81000.0, 81000.0], [3000.0, 24000.0], [4500.0, 49500.0], [15000.0], [180000.0],
                       [30000.0], [81000.0], [309000.0]]], [
                      [[7400.0], [1350.0, 1440.0], [2500.0, 100.0, 100.0, 100.0, 100.0, 91.0], [2400.0],
                       [200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0],
                       [2800.0], [117.0, 200.0, 200.0], [15200.0, 800.0, 800.0], [2800.0, 2800.0], [1200.0], [1800.0],
                       [4800.0], [4000.0],
                       [1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0,
                        1200.0, 1200.0, 1200.0, 1200.0, 1200.0], [10000.0], [6371.0], [3200.0], [1440.0], [2100.0],
                       [2000.0, 2400.0], [798.0], [196.0, 1200.0], [800.0, 800.0], [119998.0],
                       [3987.0, 100.0, 100.0, 100.0], [4800.0]]], [
                      [[10560.0], [400.0, 200.0, 200.0, 200.0], [300.0, 300.0, 300.0, 300.0], [5000.0],
                       [3500.0, 3500.0, 3500.0, 3500.0], [5000.0], [180.0, 130.0], [10000.0], [123000.0], [3600.0],
                       [1200.0], [5000.0], [200.0], [4800.0], [4800.0], [800.0],
                       [600.0, 2400.0, 2400.0, 2400.0, 2400.0, 2400.0, 2400.0, 2400.0, 2400.0, 2400.0], [800.0, 800.0],
                       [10000.0], [100.0, 900.0],
                       [200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0,
                        200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0,
                        200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0], [1440.0], [2800.0], [6000.0],
                       [3600.0, 330.0, 330.0, 330.0, 330.0, 330.0, 330.0, 330.0, 330.0, 317.0],
                       [1200.0, 1200.0, 1200.0, 1200.0, 1200.0], [42000.0],
                       [1500.0, 2400.0, 2400.0, 2400.0, 2400.0, 50.0, 300.0, 150.0, 150.0, 150.0, 150.0, 150.0],
                       [3000.0], [2100.0], [20000.0], [2800.0, 2800.0], [600.0, 600.0, 597.0, 330.0, 304.0], [2400.0],
                       [2700.0], [800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0], [12000.0], [1500.0, 1500.0],
                       [19000.0], [1200.0, 1200.0], [2700.0], [1200.0], [480.0], [1000.0], [400.0, 400.0],
                       [2400.0, 2400.0],
                       [200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0],
                       [200.0, 200.0], [64.0, 30.0], [400.0, 400.0, 400.0, 300.0], [1600.0], [1200.0, 1200.0, 1200.0],
                       [200.0, 200.0, 200.0, 200.0, 200.0], [9000.0], [7000.0], [1440.0, 1440.0], [10000.0], [2400.0],
                       [7000.0], [6240.0, 5760.0, 5760.0, 360.0, 360.0, 1440.0, 240.0, 240.0, 240.0], [2800.0],
                       [20000.0], [1440.0], [28800.0], [4000.0], [180.0, 180.0, 180.0, 180.0, 159.0], [2800.0]]], [
                      [[3600.0, 3000.0], [5800.0], [3498.0], [2000.0, 2000.0], [5000.0], [2500.0], [12000.0], [11200.0],
                       [20.0, 3600.0], [20000.0], [275.0, 9650.0], [1760.0, 1760.0, 1760.0], [8000.0, 800.0], [3150.0],
                       [5600.0, 5600.0], [3150.0], [350000.0], [28800.0], [2800.0], [80000.0], [190000.0], [30000.0]]],
                  [[[2000.0], [7400.0], [7000.0], [300.0, 8000.0, 400.0], [8360.0], [200.0, 200.0, 200.0],
                    [1200.0, 120.0, 120.0], [3000.0, 3000.0, 3000.0], [4800.0],
                    [810.0, 810.0, 810.0, 810.0, 810.0, 810.0, 810.0, 810.0, 810.0], [800.0, 800.0], [260.0, 260.0],
                    [800.0], [2600.0], [14600.0], [800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 397.0],
                    [8000.0], [20000.0], [200.0], [2750.0, 2750.0, 2750.0], [28800.0], [215.0, 2000.0]]], [
                      [[3588.0], [5000.0], [2500.0], [6000.0], [15000.0, 15000.0], [9000.0],
                       [2500.0, 2500.0, 2500.0, 2500.0, 2500.0, 2500.0, 2500.0, 2500.0], [6000.0, 30000.0], [3600.0],
                       [26000.0], [400000.0, 400000.0], [3600.0, 3600.0, 3597.0], [6000.0, 6000.0, 6000.0], [5000.0]]],
                  [[[2000.0, 2000.0], [32.0, 1600.0], [12400.0],
                    [1391.0, 1050.0, 60.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 1200.0], [300000.0],
                    [13000.0]]], [
                      [[528.0, 9600.0], [400000.0], [15000.0], [1600.0, 1600.0, 1600.0], [15000.0], [32000.0],
                       [30000.0], [30000.0], [15000.0], [24000.0, 40000.0]]], [
                      [[3000.0, 300.0, 800.0, 357.0, 115.0, 288.0], [15000.0], [1600.0, 5000.0], [38954.0], [4271.0],
                       [1951.0, 1343.0, 2000.0], [10000.0]]], [
                      [[1200000.0], [9997.0], [12000.0, 60000.0], [81000.0, 81000.0, 81000.0, 81000.0, 81000.0],
                       [7440.0, 180000.0], [9000.0, 11963.0]]],
                  [[[1600.0, 300.0, 1600.0, 1600.0, 1280.0], [81000.0], [100000.0], [232000.0], [42000.0]]], [
                      [[48000.0], [1600.0], [1280.0, 1280.0, 1280.0, 1280.0, 1280.0, 504.0, 1600.0, 1600.0],
                       [54000.0, 54000.0]]], [[[12000.0], [1600.0, 1600.0], [5000.0],
                                               [1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0,
                                                1000.0], [2000.0], [12160.0], [52800.0, 60.0], [12000.0], [2000.0],
                                               [12800.0], [18000.0], [5850.0], [22000.0], [18000.0, 62000.0], [20000.0],
                                               [1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0,
                                                1000.0], [10800.0], [180000.0],
                                               [1920.0, 1920.0, 1920.0, 1920.0, 1800.0], [30000.0, 24000.0], [30000.0],
                                               [19960000.0], [65278.0], [18000.0], [240000.0, 240000.0], [1000.0],
                                               [290000.0], [26710.0], [13000.0], [3300.0], [150000.0], [4000.0],
                                               [216000.0], [80000.0], [83200.0, 72.0], [20000.0], [20000.0], [2200.0],
                                               [6000.0], [20000.0], [2000.0], [3200.0, 3200.0, 3200.0], [20000.0],
                                               [20000.0]]],
                  [[[200.0, 400.0, 400.0, 400.0], [16620.0], [19000.0], [250000.0], [350000.0], [300.0, 2400.0]]], [
                      [[799.0, 28800.0], [4500.0], [3000.0], [3000.0, 3000.0], [4500.0, 4500.0, 4500.0, 4500.0],
                       [300.0], [2400.0], [22500.0],
                       [11520.0, 480.0, 480.0, 480.0, 480.0, 480.0, 480.0, 480.0, 480.0, 480.0],
                       [289.0, 1200.0, 3000.0], [2800.0], [4800.0], [2800.0, 2800.0],
                       [200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0, 200.0,
                        200.0, 200.0, 200.0, 200.0, 200.0, 200.0], [480.0], [2400.0, 2400.0], [3600.0, 3600.0],
                       [42866.0, 48888.0],
                       [800.0, 800.0, 800.0, 200.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0,
                        800.0, 800.0, 800.0, 800.0], [35700.0], [6240.0], [3500.0], [2400.0, 2400.0, 2400.0], [4800.0],
                       [5400.0], [4800.0], [1200000.0, 1200000.0, 1200000.0], [800.0], [3000.0, 3000.0, 3000.0],
                       [200.0, 200.0, 200.0, 200.0, 200.0, 200.0], [2800.0, 2800.0, 2800.0, 2800.0], [2800.0]]],
                  [[[4760.0], [8000.0], [10000.0], [300000.0], [400000.0], [250000.0], [70000.0]]], [
                      [[2000.0], [1600.0, 1600.0], [10800.0], [6000.0], [1400.0], [1150.0],
                       [7200.0, 7200.0, 7200.0, 7200.0, 7200.0], [76.0, 200.0], [200000.0]]], [[[4000.0],
                                                                                                [400.0, 400.0, 400.0,
                                                                                                 200.0, 200.0, 200.0,
                                                                                                 200.0, 200.0, 200.0,
                                                                                                 200.0, 200.0, 200.0,
                                                                                                 200.0, 200.0, 200.0,
                                                                                                 200.0, 200.0],
                                                                                                [400000.0], [8000.0],
                                                                                                [290000.0], [250000.0],
                                                                                                [28800.0]]], [
                      [[15000.0], [50000.0], [250000.0], [3600.0], [5000.0, 5000.0], [6000.0], [3600.0], [460000.0],
                       [6000.0]]], [[[3600.0], [300000.0], [250000.0], [37000.0]]],
                  [[[54000.0], [74000.0], [24000.0], [250000.0], [250000.0], [250000.0]]], [
                      [[2200.0, 2200.0, 550.0], [9800.0, 800.0, 800.0, 800.0], [6000.0, 6000.0, 6000.0, 6000.0],
                       [3600.0], [6050.0, 1200.0, 1200.0, 1200.0, 1200.0]]], [[[1500.0], [70000.0], [3300.0]]], [
                      [[8400.0], [22400.0, 144.0, 3200.0, 40.0],
                       [320.0, 320.0, 320.0, 320.0, 320.0, 320.0, 320.0, 320.0], [53280.0], [1200.0, 1200.0, 800.0],
                       [49925.0], [54000.0], [68000.0], [4500.0], [40000.0, 200000.0], [20000.0],
                       [1200.0, 1200.0, 1200.0], [7200.0, 7200.0, 7200.0, 7200.0, 7200.0, 7200.0, 7200.0, 7200.0],
                       [6750.0], [10000.0], [1200.0, 1200.0], [99000.0], [400000.0], [27000.0], [2240.0, 1120.0],
                       [960.0, 960.0]]], [[[60000.0], [250000.0]]],
                  [[[240.0, 660.0, 540.0, 720.0, 600.0], [600.0, 770.0, 1386.0, 600.0, 600.0, 600.0]]], [[[18000.0]]],
                  [[[800.0, 800.0, 800.0], [280.0, 280.0, 280.0, 280.0], [1500.0]]],
                  [[[81000.0, 81000.0], [800.0], [600.0, 2400.0]]], [[[7000.0], [11082.0], [2176000.0],
                                                                      [81000.0, 81000.0, 81000.0, 81000.0, 81000.0,
                                                                       81000.0, 81000.0, 81000.0],
                                                                      [40960.0, 40.0, 84.0, 66.0, 60.0, 54.0, 2560.0,
                                                                       2560.0, 2560.0, 2560.0, 2560.0, 2560.0, 2560.0,
                                                                       2496.0], [72000.0, 144000.0]]], [
                      [[10800.0], [4320.0, 11520.0, 360.0, 4104.0], [1900.0], [120000.0], [15997.0],
                       [81000.0, 81000.0, 81000.0], [2000.0], [15000.0], [10000.0, 5000.0, 25000.0, 25000.0], [2000.0],
                       [2500.0, 2500.0], [144000.0, 144000.0, 40000.0], [3600.0], [2000.0], [7200.0], [28000.0],
                       [3984.0, 800.0, 5584.0], [20000.0], [7200.0, 7200.0, 7200.0], [500.0]]], [[[4840000.0]]],
                  [[[1200.0, 3600.0, 3600.0], [16410.0], [2000.0, 2000.0, 2000.0], [80000.0], [573000.0]]], [
                      [[7200.0], [60000.0], [2560.0, 2560.0, 2560.0, 2560.0], [20000.0], [2500.0, 2500.0, 2500.0],
                       [22470.0], [20000.0], [75000.0], [1200.0, 400.0]]], [
                      [[960000.0], [129975.0, 330000.0], [39610.0, 10711.0], [700000.0], [50000.0, 120000.0],
                       [920000.0], [240000.0], [220000.0], [435000.0], [2391.0, 105207.0], [220000.0, 820000.0],
                       [400000.0]]], [[[30000.0], [12000.0]]], [[[16000.0]]], [[[54000.0], [9600.0]]]]
    time_windows = [[1734418355.0, 1734420155.0], [1734420155.0, 1734421955.0], [1734421955.0, 1734423755.0],
                    [1734423755.0, 1734425555.0], [1734425555.0, 1734427355.0], [1734427355.0, 1734429155.0],
                    [1734429155.0, 1734429600.0], [1734433200.0, 1734435000.0], [1734435000.0, 1734436800.0],
                    [1734436800.0, 1734438600.0], [1734438600.0, 1734440400.0], [1734440400.0, 1734442200.0],
                    [1734442200.0, 1734444000.0], [1734444000.0, 1734445800.0], [1734445800.0, 1734447600.0],
                    [1734447600.0, 1734449400.0], [1734449400.0, 1734451199.0]]
    dis = 2
    zz_car_list = []
    zz_deliver_interval_list = [600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
                                600, 600, 600, 600, 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
                                0, 600, 600, 600]
    ems_deliver_interval_list = [0, 0, 0, 1200, 0, 1800, 1200, 0, 0, 0, 0, 0, 0, 1800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1200, 0, 0,
                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    zz_priority_list = [20290, 20100, 20370, 20310, 20300, 20180, 20150, 20200, 20230, 20170, 20080, 20030, 20270,
                        20140, 20280, 20120, 20360, 20210, 20240, 20340, 20110, 20090, 20380, 20130, 20390, 20040,
                        20020, 99999, 20050, 20060, 20350, 20160, 99999, 20190, 20220, 10080, 20010, 20260, 99999]
    ems_priority_list = [19999, 10320, 10920, 10130, 10250, 19999, 19999, 19999, 10780, 19999, 19999, 19999, 10220,
                         19999, 10040, 10050, 10760, 10020, 10390, 19999, 19999, 19999, 19999, 19999, 19999, 10010,
                         10770, 19999, 19999, 19999, 10280, 10240, 10740, 10350, 10910, 10410, 10540, 19999, 10660,
                         10750, 10860, 10550, 10570, 10560, 10710, 10720, 19999, 10680, 19999, 10260, 10530, 10230,
                         10900, 10970, 19999, 10510, 10310, 19999, 10980, 19999, 10210, 19999, 19999, 10690, 10490,
                         10670, 10880, 19999, 10520, 10340, 19999, 19999, 19999, 10180]
    detail_port_num = []
    deliver_plan_time = []
    detail_id_arr = []
    insert_time = None
    total_sub_data = [[['08fc7bfbe37045e8a4f228bee12b28c9']], [
        ['4905e4cc8e864b9aa4165948ed5c725b', '5f29e5b908714705809e739f6e5cddd3', 'c6281a5b7c544cec941995f230ec22ee',
         '33ed4b1f3349415b8d10e17fba56e9e9', '5a6c3562f181488f9095ed5e4479e1d9', '36ee7d8125d043928b9cc7e460bb005c',
         '8f281fb8c4d1492d939c0bd578148dcc', '0fd0741a40eb43c49d4ca1fcfb9531ba', 'e74663bbd96b4b3fa8dcdef5a79868e6',
         '093b4584dc69469fad47049483b234e4', '84a546d7ee1a42fea82f1c9933b5e6eb', '31f6ed10ba414875a6e45937b3d3f2e7',
         'ac8379f9205240099d4840064afc3d1d', '855dcdd104b048639940f7c794ed3e10', '8d663c91ad7e49ae9ef0ee5fdda42625',
         'ecf4b6b490f943a98de2ac194b23b8e2', '6f2e138d3d50486a9131a87b6b7fd087', '112ade8101e64d98a7d99a4596790034',
         '437e6cecf3d74f04a942beafda4c18a8', 'd683323f5b5f4f1cbb9f15591b7ae7f4', '8f1f94fcb950481ca74b8b245ceb24c9',
         '1c491528e4d645b8bfd8474e534c2afe', '2955945a70104df68116b39c033f2337', '4d509afdbcab4281a056ff762510b5ed',
         'a7a9766fe6ad4012946984670ce1f26d', 'afa84bde76d3480b8f4709de1ca6b5dc', 'd29fec726b48405699056eccaa1e24c9',
         '0d47cf64148d46f0be81136ea394d75c', 'eec47e74ef18442189545c528f1d161d', '5f13b56e0deb4bd684f1feaab12c158a',
         '5111a173f39f4b2ba43f2f3bbc268da6', 'b3d64bffe8fc4facb56d2dd0e1d13bff', 'a222069ae15a434d99f07e8cb796096b',
         '1a6e3d735f924f98bb417bf7b20ed1e0', '199b6c11418645f89f17d0ca98f696ae', '74ba01df51e646d6b5302ff4a6dbe03b',
         'dca1d19b19d04c39a1588950239ce27d', 'a2f92cd108e54fb5b36ddb30e6bb44a3', 'e9d9270f3af541a0b2de2fe946206064',
         '77b237f05425413797d5e3d4c5a8a0ee', '948ba468f8564d829dc0ba514c3cf558', 'f53e9b42ae224adea036232b75938c0c',
         'b907764f0b574c5aabfd849301bd1fd1', '21fa5e7414b7469ea6679af465928098', 'b58d15e3a50a4a25b44b654042ba1e52',
         '080d7f28ceae440dba9c136e91cc210f']], [['57ad98b569554de19ff657acdef3c512', '78f1cb0b8e404c3285364748906008c3',
                                                 '3cee80f0b9d940afb6c6362d67ca0e57', 'f6f797a5552348b49de38207d7387111',
                                                 'efccbabc944a48ea84e70c68fe9c809c', '36911599fc4b47ee8219514e5bbb38d2',
                                                 '35f29a920298413a8aeb519b4802a020', '7458bffe3b5749a38511c2ec2968c05f',
                                                 '21f8d4125a5c423ea67c45bafef650b6', '40e8e6745ea841e6972af55a2918e839',
                                                 'd77e9166b58946a9a01f8962976af70b', '2ee99856353544f2bd4536e96bb3dbf6',
                                                 '2b81ed5394ba457da97052f0484b63ab', 'fe6a19c8e8e646cbad8c62482d66e7a4',
                                                 '97422ec288324629902df91d2ac228d9', 'e483fca5f4e34b309a727bb95bf6c49e',
                                                 '5ac2ffbe68f64eba94678484e058c58a', 'c45c0f0fc65741e1a99f35a4e85262f8',
                                                 '0f60b3cee11e452995bfb2c4d6e4775d', 'd1105e3129dd448286f54e5da564e276',
                                                 '848441dc4a7942ada6ff5a1cd4b2e381', 'b6584962882c4ce49487169e7079fdec',
                                                 '6831564ab6a445e7a874220eb6dc8a99', '5a3b3444190e41ae8eedfed76964660c',
                                                 '71903e5071414f41b665bf42b9d0de55', 'b7e2fde4a1334d07ae880c23f11b1229',
                                                 'c362f8a862644a39bcdccd72c12d057d', 'a29207b0c56e4af18107df20a32e084f',
                                                 'b5a75cb73a1d4c8592f71d25a9cb7dff', 'dd42c8a4e4e94645ac534fca138c2529',
                                                 '1d1167b603c34ce88bdc8ed4e0f166d6', 'fa9f1945b3964213bdb29f337c9fd354',
                                                 'f541506f64e440e18755fc61d9008290', '099ad8ecdcdd4dbaaf81e71d0af06c80',
                                                 '51c8f6609c284c428bad1f17cdbc92da', 'fb59c1750c8642faa66127e8b64b4d3e',
                                                 '5c5f60a52ee44f4f9bec6d975d1dbe9b', 'e02e8c3bbf26402b851814818ecd9666',
                                                 '727ce601a9424c648c027cf92bf2244b', '6f6974d164394193a738160a18dafd6f',
                                                 '32b9747199e4473f9847d4946573dec1', '6e9f9831c2c54d9fa25bdade2ff8646b',
                                                 'fcf9b5fabf31480f99b6381c93f62009', '13e50ae62af141b0a617388f1b447a5e',
                                                 'e2fa60c8e85347848ad3d7a0d0084d2e', '268f2ad9b650427097188ef0731f9c84',
                                                 '9e013680a63143b38fae2bbce520195e',
                                                 '3d4da5822a3f4e60bf94258356c6e7be']], [
                          ['1ae5cfc301d946d8b438d8daf1b7e9f3', '18400d5f42d54221887e43f6d560fb89',
                           'e1a86baf6ef9450d92a2b9f9d0a3e528', 'd5b5de99584d46779a10f064362217ec',
                           '1890d162a75243198c34147c3138794c', '796d60b8fc764d498e4fbd41ca11b172',
                           '3981409570af4d75bcbcb21e975eac80', '1d518cf3941148c9bd2b7ee0ee478b42',
                           '49dcdeef704d4295b2cbe42f3f691ac2', 'e117bb58070048b588edfdeb78e5036e',
                           'e354fa184fd848aabe8e4de0d11c6f7f', 'b4f7d2a4bdfa4a908a8e44618571da89',
                           '87f3cb616f5d41c193af6ebfc13fd11d', '0675321f8d6f4a688f700b724dcbae2e',
                           'e14a59ce00e8484c91c11955984c3c79', '34effaf72bb248e089282d0ee4bfab0d',
                           '2fb60419ce5348049e2b4be0087f6158', '013f40877086438d95a693c274ed5b00',
                           'a1d2e6562774449595e16f0d23dd8e1b', '7465d3c2ff314b99a55a29cce277f47e',
                           '15cffb14967144728a5039249abce983', '42b13ce084ab41b7b46ed25c56834d1d',
                           'ae1c6d05518b4f15856cdfd07e1d4382', 'bf2701e6116a482990e9dc5d68ecdd0b',
                           'b7bfa4b977d24281897261e4184293fe', 'dcfcaf6969de46ed987b81e0e77e914e',
                           '65b2664745b442ada19b900823e1ad14', 'fea145088e4546538e699ca4f0550ebf',
                           '7c2747ca0a7a4c39a1e62b4248939d1e', '6efbe1c2a6b546eea02066d546152fcb',
                           '14e009cb366748d58fccafad86842207', '36aa82edecf84d8d88128141818c8393',
                           '23bd8a3a02944d679c6f110636d44611', 'e30bd280cec14993b5f24084168cba74',
                           'c5c52bac8e4b457e85881d53892c9bf7', '08f8d7f308c946e7ab3599788424fe74',
                           '9ca82333f8f64acfa03deb4310ae07e2', '68336ef153f444289550d15a6262c482',
                           '3eee3a04d7a040ca9e45487befbff2d8']], [
                          ['5680eb216f1541aeb12cfa25c1a28071', '78ae4e346d8d474084d3ca0e62e30a5f',
                           'e2ad2937f22d448aaff9bd5e7eb1bc2b', '2feca0365ca0418b9e619af4ab58f09b',
                           'ca6ebbd3d0954c64b70dafd410868ae4', '0e7ea22799f142da94a8ad4490a12a34',
                           '20f492c64485412b9a748d363e23882e', 'e6bbfb20f4f848578838ab273c8a642b',
                           '4801fe8a673e42c18320280da04309ee', '29629d3b0ef84179b3630d387ae7f7cf',
                           '734ea12d683e4c839d22d897fed494c5', '6b97107986ab452cb336fefb6e92d646',
                           'e69c578f35c34ed9825efbeed1dd884d', 'f67dbe2d50a24cfa93f2323acee7e335',
                           '7fd12af648e2407cade7b7910a1fe8d6', '6b1af3f9e4d64bc2a373eaa30a452e47',
                           '04724b93bd88435384fbced0cb19c471', '0550159db89f4bf9ad8ebce1c48ff6ab',
                           'ec909ff264fb499a9ea277f550f57411', '8b30a17c9e744e2b959b7ee3a1d2bac7',
                           'ffe5603baa134989ad8b165ddd4a09fb', '5f92614f1ca848b1845eb33c81b54ab3',
                           '8996a79ea84d46ec88fcc6187fc21c47', 'edee1e6739344ca194331af6bdc890dc',
                           '6497d750cc46401e98e677145a4acc12', 'b992d01e79f340259a8a3351e97eaf53',
                           '8b5081bd1d944d81865e244155006df5', '9140ac604ef241e681735a0c6b60e414',
                           '4b38965f1dc8473d8fee2597ae8ddfee']],
                      [['f3e0be949b194393bd2c09576deb1524', 'be75eb44fb4c437e92e04a35f7fa58cd']], [
                          ['4d794cbfe6ba4ba6aa73bba041da5c23', '822f7b3fbbf44bfbac51a308c4675280',
                           '0aef815a06f84d50b77fabe82364377d', '8e75b7c0e2cb4fe890bee1948461aee7',
                           'a944a119819f40fa9ca2ff120d1319e3', '74ec88fdb4264429a827743c09b33451',
                           '12e7f2e0bda249a885ec7b21211fc511', 'b21381e85dc2470e9e790479cd3fdc56',
                           'b668726c8c954db28e9c1fd260f3791a', '9b5b8ba4c5614c318b0496fa5deff9f0',
                           '4ae5effc925147938f7289f57230eef7', 'eb9a63d06b3d41ee905c4c80011fe991',
                           '8eb0f371da1b4fc38f8c9d7a46971336', 'c391faac97494310bd794e43798b2321',
                           'fd6d6bf23adb4947a00887a047d941c7', 'b8d45218676c486b86f9643a8fcf1582',
                           '964c8b96ea9945e8bf5ad2a893c55feb', '59ae8a3685b1403082a369e8842ee513',
                           '7696d379461e48c7a519cd3e41c304b0', 'eb2508a58662419f969e3ca1728dfe1d',
                           '523c98a5fe0c48afa35604b1802e64cd', 'aa3d0ad019ce4e2aa5d62c508d7631fa',
                           '995244781fbb4a5aae11d149e4ab6c7c', '6506438ff5544c1481cc4711563eca63',
                           '001bea807b1045adb48b6be25f92b632', '3638f5505cec49f886571eee93115da6',
                           '385fa671ec46447a8ac55e2aa8045db5', '5add1b02357648de86a961657db48459',
                           '6a9c0faab0bc4582810a2fec087c609b', '668b50d671334c85a966f421ce1782ad',
                           '05448a38d7064f7d8f17b235429a0a7e', '8ac006cbb7e5401b814d9e5b68283842',
                           '57c5cd439c164ff4b1d74fd833845653', 'orderdetailtest000004',
                           'af459809254f426ca2665d94253d3f44', '0f45e1c0a49f4ddd99a586ae2be66b50',
                           'bbd9cba81b1446cf915d256e554b1c73', '0d210cb1f6424b548f9f080c9f6b2ef1']],
                      [['978da0999dd64ebc9e14ddf8e4cb9b64', 'bb9fbd18a72e4a95abb627d8608a6c7f']], [
                          ['73dfaa74251045888e602b544bb48a3f', '5e2229541c994f82bbcba386d97dccf7',
                           'e148abf8be404a4b90ee73398714a66e', '3aef3b8abe0645468ca17b85332a8da7',
                           'd39af670b33940fbad2ed228f19c607a', '6f59360162624bc889138de923046cac',
                           '64b3abec0c0940c3bafc81bb3c3cf1cd', 'b0195295c69b40fcaf4558691e8852cd',
                           'a46f6da757474d49a0c1e581c40affea', '822c9c5ea6844581b43c7a9dba8b90fc',
                           '1b433c02fb3a4095964f3e8af73eb444', 'd68adb30d4664d968babdcc5376d591d',
                           '60b28d7636a24824a3ce0f2e52ef4c8a', '9388559e5f3642cc9a93001eae80f346',
                           '6c630dc31a254c32bd144cdaed0f2aba', '3081dc9455a94f4aa9e884b63088e611',
                           '27ddc3f896bb4d358c50ef412db4e387', '42b0c5662e214f4089ddc5f11094a0ff',
                           '715eab0e85984952b3c166a0c628542c', '4060e74229d74cbaa9dc8dfc17ea4ac4',
                           '65915a016523459c8a0844fdebc55761', 'eccc84f35fa84ff4b84c1ad52870ce51',
                           '385995b8aa7346c2b5f96d0b7242c42e', '8965ddbf1afa4272a76fe29a3c9e63ef',
                           '7033e56c73ee48edb76fa12cc4110dcf', 'b7932a6c909144ba81d5113f72d7f80e',
                           '1ca0e5a6676a4e10b94ad615fa73b1f6', '292216f4a9704d8f8987ee15b20b176d',
                           '686fbf820bd64336ad0f4efd7844127d', 'edf653a7362848d7a95fd1defb8856de',
                           '2e1f6c6ba7394d75b2223c04c6b0038f', 'f2330f9439d34376ad2b41d94ee8ada3',
                           '37c62969948e4009a4d33049de1f6cfc', 'c482b49183ec41268bb993d839321be1',
                           'c4924b0cb28740a99c318ac87be5c110', '4d1a9313d0f74b3d9e21916b0d92e185',
                           'cb80b132d2f743a88644c5b1d4bfe185', '11a29ed4b9ae461daf554dbec9f59631',
                           '601674498d1f4162974e1aea266380bd', '2e1857a2f9124c3c936f4e9fcf2e47ae',
                           '52609d2223d3492fa25352e2cabb6c01', '8fa391b8e5d2404e8dac06bdc5c7b292',
                           'b0c11c8cfae34fc29cbbfac98839bdd1', '9af1571dd1d9412da81907b3c3efb85e',
                           '3ca1bc3e7def45039f9bda9a3d746559', 'd2ddd8183cc74811b2cc4cbdbe8b83a5',
                           'b7db4ef9773944d59697ef0ba80db298', 'fc7e53a739794ce49262a0a4072a95aa',
                           '562a3dc781674948874ef595b68ab966', '4b02a0fb2b20434bbe930cf90396d102',
                           '011c5b46e7084868a598c95dda13af56', '868dad8b95d04c62a9e86aa07b7feb30',
                           '1e91e2c74f594121b1b1c37f9f01b6b7', '41a59816bdbc4db2a6bed28d2181e9dc',
                           '37203dd58cd54188b4b33df1525d4282', '6634cd96258a4e5689eabbd2437cde73',
                           'dab5e0240e454fd6a4392ce4a3a3f48c']], [['644e20a21bf3409cb514774d3547b812']],
                      [['332a8328b6434a2380417ceb9bacba7c', 'da3b03750e274898ab3d7e60dfea1b00']],
                      [['80df4f826e1b485693c8ee312c29f97e', '96b1a3f2a8c34c32aa96b9985736665f']], [
                          ['a68e5df0d2f04b2799b6209803f81325', 'e55eb1f6d3a849dcbe87b3354be0951d',
                           'c7509d8d8d014a189e68a8a47d799318', '36d251b131e74c3bb98337843b555adf',
                           '60d9426f4d7a4bb09debbd4bb606fa3e', 'f12f02234b91481c9e1bfbc360a07f3f',
                           'e83b12d282b64ee8978761e10f2f884c', 'c48a1d8094dd46378b181677032cd108',
                           '8cc09735ffa84fa280b44a42e5e7ca7c']], [['450cbae0f8dc4405b77b56bacf410993']], [
                          ['9c1f93c2bbe64f5d8dc05834da24aaf2', '6372358d72e247a381e557b0f7ccdfaa',
                           'e10275606aa54551bff05453fd6e6dd9', '0b19e582693a44928af831e1671c6fd6',
                           '20a9396c80804495ac43499631b1a4d4', 'f706938e78284f2badf0e074558af8d2',
                           '0a7a8fba6b0b4896a92eca39ab149d0c', 'c51cb29f3abd47bab0cece06cffc5b19',
                           '735df93adb664c6ebeb0f80c25a54196', '577705367ca241afb9e9341d01b9abff',
                           '65b0176ca2404449b859c15d7f954475', '24303ce8c52a4ae79bfd3280706ad7da',
                           '89db7314a05b4f5e9486665547cf474d', '1416a359c8d147d38ddfec278ba2d848',
                           'a7903a0f3dd44119affe83459e93af27', '9670641b368a4091aecd2078e6e6d461',
                           '6a9b620123cf4a94916dc6fefd104e16', 'aaea42a84a7740218c0f71242e856c24',
                           '5920c11e0db249028005b674566d3de4', 'edeef218b57546f4b85cc3c69e65e097',
                           'cb909258ac4f40c59c0232ed53c96d91']], [
                          ['6d5f301a6aeb48f8af9e11fa4465d0e5', '408ac94d5f87442e876d29600128b0f6',
                           '4faf8b4bdcd041879461a8eb9bd178e9', 'd8c5796b91ab43a4a792b6e0e833b0a6',
                           'ffc66ca030004237b57b9e38940c2d4f', 'e4f04fff910d4d6e93ba9b1b667a4ce7',
                           'b7e950e7aa3a45eebe6df221058b9241', '59cfa6e7d252461f9b726c4b652b07e9',
                           '9336bc1d49ec4c75b2767d428e8d5fab', '21d774fe099b4051bf8cd4d002fe6655',
                           'e69ddd73d7a2465aaee47e8f788a8565', 'ceaaaf7515d1441d8dcbd4ada7eca06a',
                           'b2793993fd044729a97692ac82787196', '99707afd21324cebba7a9aad2dec15c4',
                           'f73159bd872542148d564ae2c3f3e959', '892363fdd3a34df3bfbbdf9118fc2c93',
                           '9b632c99fd424d61b1db7db567042c81', 'e8f3cf45fe7749bf892e555758983080']], [
                          ['e334f25bb52849979e5e55de9a366cfc', 'e6c72bd5f6164092863fd3053b5d678c',
                           '9e9d50fc51ff4a39bb7209808ffee0b8', 'b52c5f2899a54dc589a73c071c2feedc',
                           '047101a8ba5249368b888d930d0b272f']], [
                          ['2f9344fa960e49c18901c3ccd6425ec2', '0e456e7243b44aed9b47d49ddfa2bad9',
                           '16b97f92322b4b478feeb196066acfc6', '2982b08140fe464fb49d6f811e41afbc',
                           '7835522e4a294e1a8ed0df3859b37736', '6bf0744b77c140fa9a73e3401509d2fb',
                           '06e35cdde6824ee5b195816a7a514298', '402f5214ec1c42b8bb18a5e049f4213d',
                           'ce0dd0894cfd4031b0acbfe223dbe0ba', 'aa2495ab1ff147048b9c03a7e618a9ef',
                           'ab94ca67dbd94c90b39c592545d97291', '97761e93ddb049a2b77916033be41d5c',
                           '2f4d1a1843f545feb769dec881f9e23a', '2646ca897a174d1684965655e35ab1a9',
                           'a51b5ef627604a2b91555de1556a9a90', '9f3971df1ca84adf85bfe57d4e356eb6',
                           '06fd945b972a4d0a9200a071422ff28d', '6a8c1d660ec34a51a5e647e90268fb5c']],
                      [['853b566d49b145eca81856bd111eac30']], [['1e5c424587904ce2be6a6e575b0f9dfe']], [
                          ['1233b476515d436ca2e98558fc8d3861', '931085e8f57e450c92775c6a8c995624',
                           'f0c0ae6e9e2647caa9c89abfd4d788b5', '705418b4f9214020b8863996ef1ab7da']], [
                          ['2ecfc6b5f68f4e878964249b888b33d2', '4f86286322fb4692af3d78023080b274',
                           'd64de1377e7a4cd891018217717a6509', 'b13d197aea2b4cc8850a2568791ce5c9',
                           '4984cc10906f469b8d9fd8de038e67dc', '7c0540836bc748e4a30539f3f313343a',
                           'd9b80a2dc614404aa456a622b16ae644', '3d17ac4318d343b99e3680b8ff4164cd',
                           '14f45068c5054c0fb3e82f8d8b1ba235', 'c314853e8f4b48f788ae56c246a9c3fa']], [
                          ['a52b52d67d3140fbadf59d8d54678567', '5c87303aeef140cfaffe538f35ca126a',
                           'eded206782db417fb136d59bf143136f', '1810de51c9074e728b60cdf00a762927']], [
                          ['63eb45bc55c34147a64f95761f814a87', '2facf5ac79aa40fea84be46f79af6a0a',
                           '64b3e7f78c5a4e9f8491a65f831b4ff7', 'b60ed68500a44c799a0bfa60571f1bd5',
                           '83a1016dfabb4b84b18e34fbfa5a42d1']], [['4319e1aa6fa54038a254e6c61e9972d5']], [
                          ['c883d3edebbf4052b9e5ee4f04d60f07', 'baa78e5721124a93aa08f4b6ed6faa88',
                           'dbc6fade38d2478086f258dfeed506be', '90c701ec2db64ad8a34c6d3b12b09105',
                           '32ef862ea960409d81de0c4dc1daab72', '7114e9a16e4d45daafd760e42ad37e86',
                           'd1a81f15bb0047c8af43c654ac024c4b', '88487cfca75b4677939ca0df0b219cc5',
                           'c7d5bf3035884990b9189eaae33c8fb5', '59138814a28c42c9a6677ebdd77bf23a',
                           '1190592d24524437900a2768607c64c4', '13d8844aec484f5da54b0c12286d6375',
                           '4595f138d4994ddeb1624f65f654b3e2', '96ac2f0ad6af44648fd73a73e56e8249',
                           'd65d5469bc104a2ea5584f429d14fab5', '2977b81634914e4abe7236b886072ce9',
                           'a108453ae7584653bd39aa2967c78862', 'bb9a01eee96a49078ed787dc48a2ef8b',
                           'd2fcb2c587df47caa1430f0b62dad3c0', '5d992f7dba8b46089d60eae7d6a5b47e',
                           '574278f3d54a4f50a1df15b7fd6d4917', 'b428fe279f85487c9d9977b15c545790',
                           'e82cc14ee8c244deb262f664bb1c00c9']], [
                          ['aa98d919c4ea4d8b88041445190621cf', '887dc12ff4724e10a80379e9f80c89bc',
                           'ca9ec5139c6545d586c0c560c7561f2e', 'f9529fb861bc4c76bfc54a3928eb0e7d',
                           'eeb4e2383ef2412fa2535556fc3e1f06', '47d74632f7654800808ab3975ea34f35',
                           'e13b9af0ad9349fdbc901bc0431002f9']], [['4a49803f3ecc4bc4bb795b8930eb637c']],
                      [['f92c54d89c0940e5930f8fafbc8f87e2']], [
                          ['4e07f96fa8354aafb04fc7022a4d5663', '369bd186a75540bfade4fb40e3d09f54',
                           '1c017fc68b1843a7ae3f2052eba67225', '57ccd569979940119fbe586612dd432b']],
                      [['d157b0e9bd2146e498c8117ea61a74e9', '83414139107942e3afa3f178006e74af']],
                      [['8273acb7234441fe8e9159c144299a7c', 'eb6e3566fd5940ea81d6c2688b72188b']], [
                          ['01ba7a7c62aa481cbe923c75f31079d7', 'dfe33b1809d444e2954879466b9620ca',
                           'cc137398cfff44bfbf34b6065ab5b3f4', '756facdc22144d72a931343ffb83475c',
                           'e568fff445014586af66f94f7006f57f', '8e7958690f374f3ba5087bfc4e80adcf',
                           '24c6d0142eef496698e662f554a874da', 'd072d1bfdebb40a5aa01275be2759916',
                           '2f38d6a2f8cb46d9bca942561cf024f7', '42105f64b94f4db6b25c8691db331c1b',
                           'e1009c4f752746558d375d2514323f57', '419e9092cc99454c95341d0e6df0fcfd',
                           '7c3c009afe744196ae47d8bfdd9e2956', '200d72f8db5b4465bb80064557853f8a',
                           'e29d06549eb5461d98fee8ca008e3d91', '3731c4c6a1d94a3d91595aa3e2b4ca9d',
                           '115bf7cb2b4949209c02217d5bfb7ef3', 'f3bdff82eeb547e1a3cdd34a4f1bb4b7',
                           'fe4e2a99b4b94e62b7000befd24b569a', '494f157da74741e98ce4b85d9247ca73',
                           '30fa1584ab5d40b4ab8e061caa9dfeb7', 'd14128d8a1294f968801653e21dea74b',
                           '8b5ae6d257a7462d8f45e7d562f7ec98', '30eeaf6f72374f5983a61060f9c30b3e']], [
                          ['c7095aa142b54a4dae95834c7df72d69', 'bf77f2e2bb50469ba793e591b23d0c57',
                           '1be9b069a2ab45638601e0766c315b83']], [['a7248157f1e44908b2a418a2c41d7ad1']], [
                          ['9af87f7289934ad19fd4c422f8ac7214', '523f7e4143db4a2f97cf0a64d2918240',
                           'c63a6a34e75b4106b6ead6644a872ebf', '28e9658f86ac4c399f029f8707ce0c11',
                           '3dfbb904916042d18ebfd9873d732700', '5b298978d2b84555a37465a1446b733e',
                           'ba1a736585ee4519bdd3b9c8dbc3cfef', '3c15fa371ada471d8a63fb1eb9d11be1',
                           'c2732e9a041c40cbbc7a98f13caf3234', 'd72a4e4fc9034450ad9df957b9ceda80',
                           '38780888c24f41b98e3fc9ea56ae0cb2', '4fe6c1482b644fde886f089f7070ba10',
                           '9d18874a42b04ac5acfc3e501875b592', '5d17697750ea41268a5fab605e57c88c',
                           'af8fee4ec6ea472db01160f1bfebde98', '9da628fefadb40d7a66ae4104253d78d',
                           '6901308dafbb439e8f66105ab89fbc14', '9d38dc84850743a1a087b77f1df71c5c',
                           'f8c698d7d3724b92abecdff576c0b43d', 'ec116b98cdcf4a8fb4059200b68a4648']], [
                          ['684875791a39487aac855bbad3187282', '83917eb1796a4e2bbee70e7a15b0c030',
                           '4e17575f50bb47f7aa11b1d8cfe495a9', '1f96317e342d4e278786fc780cdd1092']], [
                          ['5812260e149e4cc8a656c49c70f8d8e8', '1a447048a1594805be76027423124191',
                           '0bc48fec616045d0bb71509da8e920d6', '93d71152c81b4cafa5b8ee4cb1b2bcfd',
                           'c778e790644a4e21977e35d7d7449201', '3146004240fa4c2ab7e926c8690c279c',
                           'e62ddd2394ab47a58a4b57f762203e31']], [
                          ['650b69fa4de0461abd1cfbce4e94ff2c', '7536681f184c47abb19d9a03caa14ff3',
                           'de785e8df5a944b5912c1a165ab275ba', '6b29cccd13ae49288e417be9c6e935a6',
                           '1097021ef9cf479c8e4bf7b2c39e0237', '5b2d66e5c0f746f3aebb156e8e7efa7d',
                           '34810b318d2e4641bc212988ca66722b', '3c2a4fa827034ea4b2e461b01ecfbb91',
                           'ba1d6295281149a6a1bac955c223aa3e', '66b8d38f9cc740178666c4ed983ffb2c',
                           '4b7ebf3ad35b4380be9da814939f0334', '7b64ddf4054a4788b37ce3f220727473',
                           '501aeca0b4de46f686a8f4da9a8cd48b', '1970bc4adea8444b82ecd3ebf7975b6e',
                           'e356b584fc074d7bb4e1d68218eabb29', 'eef569a225c6478bbd78da1acf704e12']], [
                          ['aee19de5c28045238d0945969947ffca', '41688892d4b14938a1289ae5fa20a87e',
                           '05af54c73c754a09bce4b7428e6b8fa3', 'f88dddb72c854902a87db0dc0ecdf3fe',
                           '6402f2c75cd24e0cb55e902d475a0ee6', '1d564414715f41eebd9c6cff52243d34',
                           '01c7bc705a4f4ead9d3ff5e10e12f4c6', '58c05ba098994f18a88abbb994d903e1',
                           '024f0c285fc74d588efd80f9a9fd9862', '2882516487274e6eb03ae5ccc0d04f64',
                           'e6a4e20d72424f5f95eb23d758bc1061', '8a708ef2addb4c3886f876de0cf4c9fa',
                           '2ba4f732d3264c22bd976898019af443', 'e4197f3202ff4f149898bd8a28360ea8',
                           'ac6f5560cf2343eba7000f4ac832b578', '5baec28ea2374db0b9022e071d49142f',
                           '9332b089e3a34a68ac9b635346d62800', '925e92a7e00f40a0a956df45f00cf56a',
                           'd13cd88fe7794a1e808d9dae5c679cd0', '1da62fcffa2248a3ae4a058c3a024e71',
                           'cea9665c89284e1cbd58638ce178d85f', '70130a95adea4efeb3e1351ebb28c1a9',
                           '5b94bfb65ced4f07a211c900c01a837d', '53f46b8ea7274d7fa87b2deb50488ebf',
                           '903da53f68884c2a97e84a55932dd123', 'f65f452b8db8468cb352328144815d60',
                           '0e2dde475f8c4e219fb16261769cefa3', '1c79b75314fa4555ab88e75fc55bce58',
                           '5f91142253d6466bbaff4639f8c776e9', '9abf9c27ca634ac3b80040de65ed4855',
                           '621269945c1446659e277457140f81d6', '39368e76e3a449fda4241df7c19fbf52',
                           'bcb7b2fe2beb4eee8d380a165ecb02b7', 'c3491c80fe1c41ee9955ee4220a580b2',
                           'c30d8e2a49ad418f83d71ce6b6abb4dd', '32f9e1ed1cd3455891357af0ccb377bd',
                           '5383605e916d42329ee3346b1cb3a89f', 'af147e1c55194bef9669db1c418917f6',
                           'b148c5e6c9f545bd8c6d9fd1ead292a9']], [
                          ['e7f0404449834a18b64e87492076a6a0', '4c2baa800a124407a3c6a0b7a576681e',
                           '65efaaa50ecb4dfb85846b5f07b0bbae', 'b1aac8a38c7e4b21a9bc22883f75aa9b',
                           '2de86c884e6b48ab99c5dc6bfd049815', 'a09c1ab7d7a849989c4df79429259b65',
                           'cad86b9c521a4651b0519c940267d344', '350d63002cf74096a87b8122db672e2f',
                           '04fbf18fc7954ba190e3acb2adc548e6', '1d5c02b931f84f409b9c8417ae97db93']],
                      [['7a30ce9d722249978a12d04ea8e7f4ea']], [
                          ['8264b474fe51453e877fac6f5b397141', 'ab7386573f1d49048900708f5f33306c',
                           'd7e6fd54f58748e2a099c799e2635aa1', '249c787aab6c4ccdbe73a287dee1263a',
                           'f79625061cb44fd7bddb26c79ca38e82', '12d67c858c7149eba31b62fde5ca1891',
                           'f5539503161e48ad97a0500af42a6692', 'fe0d2b7f31584ce3bea20875d1b7f6f2',
                           '45fe06fb7dcf4980b6d24a489ac7da97', '98613f0b96294432b83e65897bf74103',
                           '757ab61caaf64950a6bc1905489b6759']], [
                          ['3e022a2d982e460aab855915d0a51eaa', 'ffcdce7f0e3c48e3944edc3284a9f0a1',
                           '28a9d3a9927a4be2b91020eee3562ed9', 'c747d6f809694bf396116eff963d0884',
                           'a3237e1719fb4e798b38ca0c756f2345', '00e5933c03e248778ee617245f5e4011']],
                      [['0ac331d67aa14f51a7b02ad1439d7113', 'a074ba39e0104efb83b2be99222dbddc']], [
                          ['d2b57001a929410fa0c902cb29dc088d', 'a1c90cb5410b4f5e9d6577ec357867b3',
                           '7b3fe423526f4b9da16b1536732c3822', '1f1c192d84154cfab098f5e534a8ba56',
                           'cd1df26a4b6848a69cc2fc76279e135e']], [
                          ['e8964e51b642442d9808db7891694292', '1ce1223750554a9db5004e6f49c26cce',
                           '4fd0ac9c388440649fc25341806dc3ed', '04f040ea612544d39b26874ce38fcc31',
                           '0921793ad4d14aa6b10f2b794c0f13c9', '5e0c395d2c4c40cf8353d9e55a0c82f2']],
                      [['e591306e46b14cf7bbc9fb097ef3b1e3']], [['04955140f8ab47fd80327e7004fb6417']], [
                          ['85e5c6df8f9047cb86f7292198fdf538', 'd0a2d253369c46a982cf909e1fc8ed2e',
                           '4d7e629829234f44836a7fbfd616b946', 'c16a3c0995ac4221a018935988e45a0d',
                           '0e6ae9d6a45c4bdc93b42b43f0164cd4', '15bbf4a326364372994c34467201574a',
                           '2da55b57e66347149705165b8f42358f', 'ae75bf66a62c40eebc06bbd06b55eeee',
                           'ac3cd28bb2c34748b31c51ad979cabbb', 'fe9b14f3c7f54e36b18aef6ef22debaa',
                           '44adf09280234161964ad0d931b883c3', '2c3458445ff6410f903d54cdf1010a06',
                           '5dd2dba2691b4c73979582e4df2c15f6', '2410cbce9cb04d40b8bb68e776ac939a']], [
                          ['3d1d89ce80534472af58d6eb72ebffaa', 'b814cfc2076d4487a454139c6c5817bc',
                           'bc5b742f759a4e7daa02e9ce5bd55ba4', '382157c893bc4adca0d336c0619764c4',
                           'fdc12abd1fae440db5bf9ee54ca9fdb2', '12bc77f4a9664b3db4e2028429a347ec',
                           '6250fd58169b4337b760643eca8c7a4a', '987a1a7bf3374ff4b4a8ba05a174f8e0']], [
                          ['ff9580a5a66242b680ef590a9449c872', '9f04d8df94394c6dac60296ab48cdf83',
                           '909eed4038004796803067d2b57bb35c', 'a721c390cee74dc19b85b6d4ecf7c484',
                           '6da33555850a42ce921f4297a98888d8', '703ee84da4b54a68a5bde780b737fe82',
                           'e94a0e1f015c4222bf58abb9272a8292', '568a421dccb44c04906387015627d6b0']],
                      [['99a13f5145404419b16353665969f917', 'd5317e19b2fa442b98158ca97d8dc684']], [
                          ['46670367ce2e4153b3310b9c556855fc', '590cb11528f24b689bd6bedea757ffb1',
                           '4512b80e536c4d55ba0c19a59b85e606', 'deff41a589f641c9b449486cdfa950e2']],
                      [['952f56f3bafd4385954e634193ae8d39']], [['419ff0d12cd74287a42302403248a904']],
                      [['7e1620137fea46baa89f8e1fd53e78ed']],
                      [['6c82fec163f54af394e9524665e61f18', 'f0c423794cc04746be8f66a1ab59c59d']],
                      [['f186e6ff18a54fff8938274305e52334']], [['9fe9db6436fb42f6a426658917a129ba']],
                      [['dd8754d141bc4e86940a35c23bd8378a']], [['c4c83e31d5db4a06aa316aa6dcc94c81']],
                      [['f33f8f80044b487f9b5db8ac34260950', '913181ff9a114fc5a2454ebe6695cfbc']], [
                          ['4900bb1fda2e41e6a28ee1c3c59354b8', 'fb0fc74e83154a8683e9710647378617',
                           'a65579a2aaff405eaec3d49fb22c7337', '276413d1ed7048e79ee3f50f08ea8dd1',
                           'b8757df033b84ac8a9142582370b46ea']], [['0783db774c324310bf7032e90a48e6d7']],
                      [['17b4fa9e24ac4f4fba2b2ba3b137dcdd']],
                      [['3377bebffccc4ba29a03f9afde95c35e', '7ea04dee6548424998a584f802d5fea5']], [
                          ['8d1461e411b041cbb551f6bf56252a56', '5fe087a06de04b2c9c2a30d68dcddaf7',
                           '7359b9a6a9bb483293a852cdcbf4fb3c']], [
                          ['b2733b7be2294033ad992a10494daa69', '30aefc3dbb3e4ceea079c7d5166d5f4b',
                           '743c9037fb404f5ca46d54135807e4c9', '8ff2bb139e2f47b9acd0f167c664d9ee']],
                      [['f8237c20176a4067bf0f2e631be76e8d']], [
                          ['dd778f668da9437ea26dd5295eb54a26', '50ab2bad14e74ef78e8dd2c7b35f31fb',
                           'e5b719044fac4ed490168a29430b369a', '47d9557c430c48e99d27d463f76f5018']],
                      [['577939d4c9fa432ca4f6f59b828d0536']], [
                          ['fa6fd79db4614fdc9e88ae06bb7b8cc6', 'df45a0084ded432cbc0d8bd1cee1f590',
                           '3bad7fd549e5447681d48944136908cf', '73aeef3c0db94cc380606de5172f87e6',
                           'e7bce738d38440a69d41135924f17aef', '30c5e54f6a094bf0a17c4aef54b4068e',
                           '7359ac824537492b863524624c58adee']],
                      [['5bd6668babfd4522b32d96d33d398712', 'c6c7445fd6404183a97c40ec60349dc0']], [
                          ['2b94db8eef64448a8d9aa6db12f64349', '9d32df6c6bf24c32bae730fb9eaa81a9',
                           '722dc1090e3743c3bef79a6fd2750626', 'e34ff98b272d4df396ca6f488bf894a8',
                           'db6d8d07930d468590e5a83e9e1028a7', 'd22b1b860cbb4d168e23601d18fb060a',
                           '095e0622c18444299c19977dce3fc939', 'b3d506570c5343f49124209a139013f3',
                           '9e5741c34ccd497d939ebfc101957d25', '72069df599dc4529afe6a56245760485',
                           '81c7ce51acca464d800f817ac3e7b597', '7bff2943e3714151abdfb5e4ce785a43',
                           'bd8f7b1deade4ae09cfe186e40143bb8', 'e980b636905e43e680115e5b3fd852e8',
                           'a6d94142331449b78ce725b63908a650', '2d6382a007d04d7faf5b5f97245233d5',
                           '51ef38debfa84a3dbc23a301e1ed6cbe', 'e3c083b4a37441fb998522f6bb4ae3f6',
                           'a589c7d728244966966f320584e8b58d', 'eba7de1415d04a298c5ed2f470b33d4b']], [
                          ['fe38a732727944dda587ce579577992a', '8742e846fc874f5494f1716f6dd824f7',
                           '31f6d2b13197458385fe4f97e01a13a0', 'df090777fcba404eaf0f4a3e478bb767',
                           '9980b43efe3d46e883942c0de801b27d', 'af77a54d9471428cbbd91a324b1a292b',
                           '4c63ad8aff624967891501c0a7cd4b4b', '22afc7ba960d4b2e8ca40c0411410027',
                           'c77f6b3a57c940339c104e23a1d5b2ed']], [
                          ['6d539cdba2f34ee19d7864a049f93b71', 'd5a36df1ec084d24b069e5892fcfd22b',
                           '55e7315c463d4b108ad05e05a77c1b46', 'ee06b41d0c22481186a526ab28f8ab79',
                           '17f0400d8637403fb8fcafae5e0558de', '1f381da852ef457d96f094551e516ffd',
                           'b687400870cc4dc5a215e81f0d3ad558', 'ca7d77b32da04a61ade9fd14bb6bb3d7',
                           '308cb20d0b68487cbe23bfc12037180f', '3886ce202d344176b557ed4fa8feb877',
                           'd30fc209c11b4ccd8161bdc36a16684a', 'ddd999b880ba49c5a38884238c267062',
                           '00554e647bd54467aef47618507fe298', 'c795163ff8754d10bb5ff5efb1adb9fa',
                           'd94902c10ccc4ac990be9f4ea2afaf3c', '06b1067e834442ad9cc89da80f18d975',
                           'c5b0c31ccabe48e28bf7dd432ef36621', 'bdd1909b3ff0437d9281b3e7c5d327cb',
                           'd812aa4c49974bddb44d79d16832aabe', '9d61d4f8dd53488fb9b87a08409b9ce3',
                           '670c2e4ca1c049b8870fa82c1557e8dc', 'f64ae43ec3e8450ea562617f9d8b8787',
                           '3cbddc0e3b0b4d1281061ed9fa578160', '1ed88479b5fe4fa9b6e9cdcfd1949099',
                           '2ac0dbe585374b6f96bfe1802fcfdf4b', '01c87098fcb743ac98870733a6c46fab']], [
                          ['71ab6f10eb7f43438f11997a705797c5', '955158e0be584c81b489f4b56751b45e',
                           '07a087ee7c8548b8afb2e9af56415de2', 'dea770f2c78246aab69daca8b82a4f8b',
                           '8efcab8d040040c993bb3259b7bc05ad', 'dd8c23f4a3ae4cf7bdfc5ac299125005',
                           '03737e36dc0a47fbbd6e05cc1c9125cc', '70dc3c8b5cf3495d91b218e44ace5282',
                           '9dd33b830d074aff8c8ca6e107215147', '97c7bc030134457aab6f7d896f6db58c',
                           'a7742ce073c34cd2968e34ecfafa1226', 'a2bfee23ede84bd199add6a9f5cdafbd',
                           'b70987c1d9874ed3a35ddbfe42b3de4e', '8cc92de0cf2d4985b0c57820efcb9d76',
                           '36f18858c08a4e0ba911b239b2de4171', '0f8d3ada787b429d9bc195ea17c7d508',
                           '2a7ecac11a3843a2aaae5b70b8266eae', '9416c041982e48ae96f5b356c49e85fd',
                           'd51291e7266f45348a5d7fed06435b7e', 'd9313cf8cff643b69c973c913361119c',
                           '5556df614bb74f96b5db7ba31006a564', '0979549ab6f7476cab4fc5745b9285a4',
                           'dc3519af14c64a7d82d50b61e606255d', 'b4601b432cb441fbbfa8a0d40ae1d573',
                           '46df549d18b74493867e29d945cb716f', '0775c45e745044a4a707cda3e57cfb45',
                           'ef71fc64674346f1a803881c470c6a90', '063ef985a3b84da2a5998f3164ec5b6b',
                           '8b2068f3107745e297b304c064bfba06', '3ba5fc68c42547488ec0538007dfa77c',
                           'cf2178329d0e4eb9b32eb4428e07f425', '00c3f23878194af686ae398f5cb850d5',
                           '949b22e094134af29488a73452bb06ae', '94942b46b6d14c15b60b3707d79477f8',
                           'e6b2b5b0d8454ac59547313f502e89c7', '7bf9a57069ef4e049d08086e0084da52',
                           '3c619aec5a2e4b8aba86cd874791ce3a', '187249150c7b44efa3613777aeaa726f',
                           'e3d560ec828b416187e98e29d29c40aa', '0a379c874cb744a29cd4435a65ae0eb5',
                           '7f3a44fbe81c4166b5ebcc1a5392f34a', '600a88cf353b4e7f8758a1bc76f508b0',
                           'cea5fbc76982476d9e1a3ea337b77891', '7a4ae15ae00f4419bcaa50e40d5a730b',
                           '2f2fa9df13d546de885e6d56478ae171', '4a551132110e4c269c2beb682d393f77',
                           '808ef71634704efca2208c529e103570', '10a804e9773c4b388dc03d5dd5efc02d',
                           'ef6fe40d866242c0a80e75f7ad9ae53c', '0b1666952cea465888d50e9f4902997c',
                           '646e110158934e8f8b9a1c53621c5016', 'd60088e50dde4741a0e71b7c86bc6e25',
                           '32da99391e2a4e2f8795d2983f59ee34', '53c1806305e242e6b3b517c4227ec905',
                           'e7c9a9f0e3534bc293017324fa1de59d', '8cda4b3f37494f1793dcb52191c9e19f',
                           '7da21400f3c84bafb9664366ba7cbf03', '8dac2a97858144b88382d8adce2a4348',
                           '726e7890673c443ca869b07e4bd2f6a7', '64de76ad1bd342d197d13403ddd50101',
                           '6ecfb9c727e64a0bae1581fb8533dd8a', 'b41571ea156f442ab0cb8c9d53c767e2',
                           '6fa7a59d8405403bb28358170a268a32', '3d48d8eced40427093ca49ca14e75aef',
                           'cc00ffdbcfa94ed6809dcacaa29f9e0d', '6fd188bbea034ec9b087a3d896dcebb8',
                           'db6d1eb80f2245a6b4b7af9ae4952f15']], [
                          ['8aae478794a94aee8c973b70ee75af47', '8c6cbd0218fe4872a5e3e1ea259bf1d8',
                           'dc304c4352f946dab4462d77c0de3d47', '9a2a479febe84bd9bc0fb80cdbdbe0d5',
                           'dac28b3a19f94e98b41f94de5ad6d3af', 'd930590e30414637b60c5e43811a7a70',
                           'df5a67540f094f27acd5d5570c486b0a', 'c384da4602f848aa84a04bbdf5b6860a',
                           '6a939d409cc243cf9621550bef997d10', '64948d64c10d4ed2a06b3d54bbc3728f',
                           '2c9a4252dba041b4a37f2b5d6de4b2ec', 'a842af29f5464663a9b7af5f4e8c9bb6',
                           '140101334017478589c0b46cdcec524a', '5089e4cfacff41b6a9621cda2aacdd56',
                           'b52f560ef4164b9abd6e02b764da874d', '31ba90eba2614cb6bd615a6b21ffe3e6',
                           '64e7b84979b044758ca32c59b274d093', 'b3f80b3ca88d4ca28dd36b70afea23d7',
                           '72521eafe3dd4827bbeda604585e0585', '1f3db6f856594144b39313eade41307e',
                           '722c1e4fc083455393c5219afd27b59c', '7b24141040334df6902829240254b77c']], [
                          ['f1bd87151de04bc7be507ac9923f7100', '9c6aa7e39f1d41a5949d016f72e50ad2',
                           '56a0565e9da7474f98ada96ea95f22dd', 'bd2507556fbb49d0b4e95c14ec7d769d',
                           'd6fdb3dd557f4aeaa5bf09026829ca22', '56bbfee7886c403d8de2fb8e0eabef5d',
                           '82dc0ca791df40ffa662e910df7d2005', 'ebdf24dee06b4abc902211651dea2f3e',
                           'e4957fdf088d48f9b50024f83937ac37', '0b80469e9a1a42b0a46158ebd40c4d17',
                           'e8d0fcc24acd41b987c5ba5776cb1b3e', 'a75d6d8e240f4c5487264e35aaf12e6e',
                           '4808221ba4c44e7d95a2c5646af48a11', '01ba017ba55442d088552c5e39679cda',
                           '8ae281b56aed4ecfa274e580f213af1e', '40c6fe7362b74467a114cdaee75b2207',
                           '692f739b1d514fe793246aae8ce04ef2', '4e08751f749a4d8983a4a5e2db7cbee3',
                           'b6d1ba5fe9674e1c8dc0ba7a6ecd79c8', 'd12f7bbbf5b24be2b4f3cf0fef38661e',
                           '51063b28238d414a9ff0eac8a31c9309', '7325bbcef1dd4f449d10b8466876a697']], [
                          ['5c4d5da4448f49ab8b58b8d086ef5e5b', '5f517f2ba16c4153a22f5b1918e11b79',
                           '60213f79444f49718d6c72b02cf4e364', '831c487cc79d49c08413a83b085aed7a',
                           'd912846a318e4a86b18028f403ca8ae7', '508b6599b0134e6e98c4cffba0e593db',
                           '2a90200d2a284bee87f925c94ef5669a', '555cc04c206044a8ba3a55421f1eaf47',
                           '501d913f877d47f1bf04355b745ba29a', '25ba7957c87642e1bbb761af12506ec5',
                           '3fc557d41b494bcbab85beacbd2b8412', '957b27f0aa7e4526b734bf8912c2c877',
                           'e7500d424f344cb6bf61abe4eb0c5c86', 'd189d7effeb648f6aeb7f5dccc6fca22']], [
                          ['9c7e089018f74179b89167da27a48b29', '65cc3e2d8c484436a9ee45e25b422c82',
                           'e92e0ecbd62949198b2cbf5a978041e0', 'c02d6609925d4ee5a2233a9ec5e382c9',
                           '33f6686021704499878246cf1736c4a6', '7e0e12e5424e4b3ba7c3bdbb85a89b84']], [
                          ['e604dea4a407445d81fa62cf1bb1fe50', 'fd04ff22a87e413086399fa83f567a6b',
                           'd0e2d31ab5d84694b3f4b197b4695a6a', '678678b6d80a4d6a80436dd01ae5f6a7',
                           'ea3a536a1db3454b8de0f73e7f15652f', '294113759d3747f28b7335606fb8eb00',
                           'e0ecedb9e8a54d63bae9448d2d71d6c0', '927dac2332164ecfae89f59d04f08e99',
                           '739114a8ac644b278047882973e80464', '896fd2663dea42daba628f8d35dc5aeb']], [
                          ['f1a33241e5b54611bb4a932786160549', 'd9d45dd519d545d3b0d4be51f8fc37c1',
                           'eaa25315280845649fbb042f541888e7', '060a9b847bad490991775c32b86a2284',
                           '75eacff8a28e4879a1bdf0495c9ffcd7', '61dd1beef43a496c8221579f709944b9',
                           '580aa9b776db46f9853a6be232a6007b']], [
                          ['a3145cb68a4b4f579cc82585f275728f', 'ce0cedb8709e4eab975b97d0ba0a3132',
                           '8080f048ffef4f1f882ddfcce6e37832', '0238d23516a747f586440cf4a995d76c',
                           '125fa743a9994eeaa3b1aa51706d2f76', 'df66898f78c04091ac4310f994b876f4']], [
                          ['7fba150622044954a4f1965ce128e7fd', '0c92656454a1487bb1f50c00d5013eda',
                           '9889313bcda94e5eac3456a6ba2e9684', 'a7ab5f48f409443bbccb3bc7b0ea3bc1',
                           'e01a63e13b0645f48063fbe8f4e2c2cd']], [
                          ['5a1e3c29371b4031b5c6bab473373310', '42ee0bfc3bdc4dc3aace201c081395c4',
                           '0672d59b545343c7a1ea87d50af9c6b4', '4772a33899d142679cee18ccd0a9db5a']], [
                          ['c0e2de7d8b144d48b08651ecb87b4574', '2e334e8466e548e28117d781d410ee17',
                           '8daf4779be9f44a9bc24325afe562042', '44e82154ef5d4680b788e32a51518dc5',
                           '7c49e09c51ab47ff9a5c61a1066598e4', 'a6d2b5edaf904d14a135ff92ee35ad4c',
                           '4ac5a9a78ab04dfa983e34cdcce00f0f', '68e01a757c1742edbef1d70e1cb8ad06',
                           '0f25b3fb08584827a243d506f27e43be', 'b53b9b5ae59548ab9cc85b6856dfc045',
                           'e40232762dbd419186562ef36e077307', '06f3c8d99bc44b03ac147d5dd191d3ce',
                           '06399693a2174369940214b5de2b5d52', '95ad8c7f460642878351c7439bdc1348',
                           'abc9a9e8d368424398034ea286bb920a', '5d1c5a1b251a4ffb94a4011ce414fffd',
                           '9c37bb03fbf3475e805bc172abad3e81', '172db463cf5d4ce39fcf8fc2f74307db',
                           'fafb6b5e60534b5ca2aa79818dcb3b3d', 'e51ec56146bc46a6a96f1e088d07f5f2',
                           'bb8b110165a54b13936914e83df3b74d', '93f35408c64042ca869241f1257c1b4d',
                           '5284dc6d26a1469f9f543f28ff86af5e', '5deba12c1ab349899554e05a9e382a6f',
                           '9fefd0a459244ac79c3ef9752c2de3b7', '896b0f360f284e8a99ed8685518a1a00',
                           '8bab05af305948858d106e1ec3068863', '2a8c841170b4423bab8bd45106c9be69',
                           'c9d5bf50737f443fb5b3151c991c6e1a', '20d7c32ebcda4f738966fa5d80072e1a',
                           '85b647a31c39449b95900dbe5c7a8b27', '27e0d770815b4ec3aea5c8cc910dfe01',
                           'b182026918754eaca8c5c92c8e42a7e2', 'e44ba57be7254edaa7ef19be01e53345',
                           '515e9fbe15f44accb030ef758b9e9ee6', '75a2bcf8a242421e998c803b3792e8cb',
                           'a1a9468f0f2143a886dbdc2c954cbac2', 'fb46407775584a05b98dd08237c74970',
                           'a0bda8a126d74772b63fb109952965f5', '62192408c37f487d8b398e16a71af825',
                           '4cc3ae73cb9846d0bccba720109a1a2f', 'f1689fd251154786bcf7bb22d4a40934',
                           '5865a97abb9543688e5e85f34a668cec', '92189f080f834ba2ad75fdcfa1dad51f']], [
                          ['95ae17de3ca1409c87a4b18014b32267', 'bac8ac0b8d3343e3b269b03920cc0fe2',
                           '1861426afb1742df96456e20b8478c77', 'd540742b24f7424eab93a2fff47318cb',
                           '2d406c20f9974575925b3fe0c4aec5d1', '99e3a8c3bb504f7ba3a68a57ea68b4b0']], [
                          ['4525d63e86f1432db856d9d64dbf1e28', '4cac65554e764cabb6600ceae9dfeb5e',
                           '6c60fb1827a0477ba6c08351c7dfe001', 'a400b4f9aeac4c9f96863a9cea7fa8b4',
                           'edb03a4888de4a2eb979ee43b172db6e', 'd09496943449491a999afa03191194d1',
                           '4ac039eb81c841c6806920f0b181803f', '27383f99e0b74adf9b6b66a2038d5240',
                           'da47ee42d5874592af3456bef493c8ac', 'fa39983566fa4a95b305f070b4e17867',
                           'f91f91290fe44ac39b30ee209f44d9c8', '57a084c2e127453e8e4b10a1d6e9be7b',
                           'fb1988ed1aed417ab0f12a18a272cf97', 'ea6f8a7490374ecfbd1e0c89d23993eb',
                           'f36fd1477dbd4c64ba63c1a63032dbe1', 'e3c75d9039e543b291e694bc62f460a2',
                           'c5b3d58251e844e581121ac820431f5a', '86ca4c982bd546a79678dd4481452f23',
                           'beac719a63a34907bf4e3309f0358813', 'cfc825e6dfc24d27b904b4c24f74bd7a',
                           'a9c6e16bc34b46e3a584aa7ec9a86cb4', 'f6db28eaa2a64d2b90f46cb8604378fa',
                           'e0c839ff414f4486b4c9be76cfa9bcd0', '78e25efdb7f546c1899991f7009a92a7',
                           '314c36894d95415b8ab025deb596430b', 'd9da91c3061a4be19a46ddc177a6d1a3',
                           'd42b4bace73b4bbe8d7dcd1cb3a8685a', '8a1c0cc8618b499fb1340c5a2afc1122',
                           '5ea9e65fdf1049b1901a40f72ab5cf59', '013a316ff81148899ecf33f9513dba29',
                           '51ddb9d8e49e44049d86e442323b04f0', 'adc3eff56ff644c2906b67325adae3a1']], [
                          ['240b3d2935814d368e0f287abde13544', '16e6fb4c8a5d4fafb810bba8786ac96a',
                           '86c97633de5b45c08c07afa4a44b0f47', 'e3163f1ca0b7438ebb51d610f3a73bb7',
                           '31e1e6f3428a424b9fc2cc084b43f05a', '357f5c3e3e92417e8f201f12d8a231c9',
                           '9247e315f81641b38ec3421b08dc261b']], [
                          ['2ce36f68dd3d4f21b7283f34b18120a0', 'bed04c77df72407fa794e1ffb1bb378f',
                           '4bdec10437384a25a0c4394fd734c3ae', 'de8d1e89811b4dd681b5cff943b02632',
                           '4066d5a445c74dba8d0af03701d343a3', '6d2fa6277a2d414396fcd84d8e16e68c',
                           'c8234115ee804ca4ad171079ca7911bc', 'c7baa10b04a64c94b827db9d75dd2136',
                           'f5771941b631435c9931a047dce76949']], [
                          ['9852c3c77b4a4360b43ba6ba3abd4566', '8887bae77a324fa1b20bf7fc206f8f39',
                           '9b9748a05eca43a68eb827475df83776', '75493688b02c477a8fb152f1b5ccfd47',
                           '482ff4e1f7294cc6a3c2249b8dae1988', 'af904a91ef2049d6ac25e933b418a093',
                           '099d88c8d59f4d6ba6873e7c5bc34dc1']], [
                          ['ee577e6a50a74e93bd9a241d60dddfb0', '5b1c953f158f40c0882c139c26c282df',
                           'd15954f57a004859b1f74f809347c2b0', 'c920b336666240d491ab948d874d92b1',
                           'da0e9edffcc3423a9a741c40769da008', 'b0165ab00a5f44d3888cf9bdaf06c5d0',
                           '9d4cc33c1f9f440cae468cf6a1aafc77', '38e8720ce7324e29b3ce9dde3d312b9e',
                           'd0ff84391003441e931d79fa875dceda']], [
                          ['e299c8e4ee424b4f9ace3aaa8c3c4b60', 'd68382490dac4972b2ef2f32879c3231',
                           '3712638ec1d04d3196c67ce5742a44e1', '42626724170743fa9cf89b26c7e9b905']], [
                          ['c22ccab1a68a4595a2af073f83fdcdd1', 'a44c1f57ee8c4f2aa152bd8d17338e10',
                           'f1bea74192434a729e6f7db997b0ae6a', '047eb1106fb44bc3ac292348d5966761',
                           'd4b3ee4bd4a746b5b9a62b7cc60f4cb7', '6f2d1750e24140eca7302724f6a48658']], [
                          ['dc291e692f4b4f5da10c470a6597f713', '801d5d1c332e4f85be55d5708192c2ca',
                           'ad061a8513af4bd3af8c87dd42a2d072', 'cdc700167e3b4ee58027057e60e73b1b',
                           '313def70ecc14959993c91c7300db4c5']], [
                          ['324895c0fcb3471a9f0da9532c51d3da', '052a38224da7442e9b5a30e66524ebf7',
                           '0758b678df754366bcb07ee7174353c9']], [
                          ['a0a1948cc43948969b8e3d9affe27107', 'f1b5bdc2506749409fe0e0ad746dcf15',
                           'cd87e3fba2634b738598a479eda70c9c', '54d8f11ea0d34990a8bab8af1c4009d7',
                           '6276f615f7454bf0b847ec792800cc39', 'dcdff4d9c8ba4caca1b789d3b529a619',
                           '3ed0ead5aba64efeab691491f093a99a', 'ac7661a98d344044a0cd28787c685d4b',
                           '02d48c47cefe4887be01ab5e8c5bf1f4', '832a697f298b43b1b3ff287521747625',
                           '8b672213d154486998635d1a95bb361e', '42ff5ef1a863496b8eceeb3f567e2d38',
                           '6c6cdb273efe44798513dafb07628ea0', '506784813a214b4da6eea12623b979dd',
                           '652aa93d89194142b52c57645f2aa38a', '66869d9f9ef94658a166a21d258629a6',
                           '86dfd6652bce4182909e97bd7f1f5a20', '57772cb8f42742e0a0ca40e85250386f',
                           '793f6ab4b9a942baa8a9523e1045dec0', 'e12252adfa8345c6a9edc0eebffbe634',
                           'd2a3708f65634592820c167778771cdc']],
                      [['2d26ebad1ce54d51b9ed882f665e3be0', 'afadf7eb2c8640d79ed9983f46be037d']],
                      [['c6f05b0a44f14006a4d4ae5656692d42', 'ebd77e05b5414bb2a617d795938902f2']],
                      [['b75c4316a4f8476f819935d936748baf']], [
                          ['31c437cf758a41f297dc2fc655ed8b78', 'c3856df9d528479f93f1d1e2e4369b37',
                           '52efc8a2ef4f46c48897f70901815c0f']], [
                          ['2e11aecff3c94ce689584e4c8d7416b1', 'c529214964654bccb0309726ec6534bc',
                           '9259cfbf586f4aa088652571fcb2208d']], [
                          ['638ed8973baf4536b22baf1e1763deea', '8a955e3a8fdc4213b9e73d651947c8aa',
                           '7bad045ec7ae4c5095a43820b9c81a0e', '7831e784aa354712a6459975424109d1',
                           '5ff36e4ecfd34fc891358001bf44b33c', 'd1a078fa74de48fd87f0bcc6601d34da']], [
                          ['b132f9960d5740f893657826e69337a7', '05f8d668661b4bb3aec26e5ae59acc4d',
                           'd1011d4dafb042818660cd3bc1c671c5', '1f5081ffc9e84b4e9e811b07897f8876',
                           'c7ffcc4cad814362b93bd5e1bd890079', 'cfc64bcadb90458ab9048d36c3dbd580',
                           '97fcd85355c6495788545c5b2693deab', '6a771faefc744435a465867e1559e1ba',
                           'e40f645ad8134d1eaa7943c8ed7a1fd2', '6a52b2aae1c843b681d2a34af45e89bb',
                           '823234a15a094265b68d057b460bdf25', 'fa52d0a010c84fe4b94523f6fa8aea0b',
                           'ed9f9d1f7c8a4ae993bd3711741b57a2', 'fd1695b582bc4286bbf40b64931383da',
                           'be123526f7744c2a864fc664b98c2d4d', '0b9d0ba5a43e4426a4f0d19cb92c2587',
                           '6e7e0613e283483fae3edeec22e00984', '8542e34488f44a1a99059ec910dbe430',
                           '513d722687b54d1cb64cef8651e71431', '5ea3337d6739463b9759a0fbdeca544f']],
                      [['e8626e27283c4fdcb691834eb5f2790f']], [
                          ['cd5ee9211ac1415baaedd4e63e5e3c65', '0fedf02447af44638d13552ec6203334',
                           '72bde6107496472b94ab406c490027cf', '78f6f4ae89f04b8c80b8d49b96ab4916',
                           'c1d32f25b27448689f7de6016ef7c894']], [
                          ['90e4071a229a44f591d899a93b6ab583', 'aa9c2b576df7483aaf1a881b2f4ddb8c',
                           '63c1d7c3adaf462eacbe05529ec2aeb0', '4f0476d3dd4141a1a8a3d450ef190758',
                           '52c16c02dd784aa8816163195cc7ffd6', '526d25e7a4154e0890a491e5af3e13d7',
                           '73fa3c1aad0249329b2653b3c4d8ff7e', 'b4fb4b5d2af74165bbab37505f2f25f8',
                           '653246bf5fc24436bcbef04255f72212']], [
                          ['6fb820957a594e5ba3e8b52d85b9eace', '759a4f91bba74b9f84bc6e2f21c639e6',
                           '601279d43e104578b90e62004e563780', 'ae523ebbd05940da8abdefd5e0f4fb61',
                           'b494c5bb77124aa691f2a05640bd2e7d', 'fcb41baa167e4acd8dcab6e03135a6a1',
                           'ee6ae3c85bd24878a0f1cc43cf3a1077', '9804d4cf2b1a407093d1f664d8f4fe53',
                           '6093d206327a42e2a1ee55172fcf0a21', '24b1c3f8f08b4485be89dde41b61101f',
                           '0a559a545b484a0aab9c7d83b9989441', '52c698fb32f849258e0e14e48b21fecb']],
                      [['7fcdece5e14d407a87bcb7a77398fa53', '3292bfb2626541f1b8e6dd8394d6813b']],
                      [['8ec56aa68cb843e381504f91ce6d33ad']],
                      [['fb255bbc9d4541f5b0f0031f2cbaf534', '78c6e72fc77c4db2b873b3cde53d3561']]]
    global_time = [[1734375600.0, 1734395400.0], [1734433200.0, 1734436800.0], [1734395400.0, 1734399000.0],
                   [1734364801.0, 1734368400.0], [1734440400.0, 1734451199.0]]
    box_flow_value = 0.9166666666666666
    ems_detail_add_date = [[[1724515200.0]], [
        [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
         1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
         1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
         1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
         1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
         1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
         1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724515200.0, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724515200.0, 1724515200.0, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19]], [[1724515200.0, 1724515200.0]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19]], [[1724515200.0, 1724515200.0]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724515200.0,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19, 1724515200.0, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724515200.0]], [[1724515200.0, 1724342400.19]], [[1724342400.19, 1724515200.0]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19]], [[1724515200.0]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19]], [[1724342400.19]], [[1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19]], [[1724342400.19]], [[1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19]], [[1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19]], [[1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19]], [[1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19, 1724342400.19]], [[1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [[1724342400.19]],
                           [[1724342400.19]], [[1724342400.19]], [[1724342400.19, 1724342400.19]], [[1724342400.19]],
                           [[1724342400.19]], [[1724342400.19]], [[1724342400.19]], [[1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19]], [[1724342400.19]], [[1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [[1724342400.19]],
                           [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [[1724342400.19]], [
                               [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                                1724342400.19, 1724342400.19]], [[1724342400.19, 1724342400.19]]]
    zz_detail_add_date = [[[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724515200.0]], [
                              [1724515200.0, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724515200.0,
                               1724342400.19, 1724342400.19]], [
                              [1724515200.0, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724515200.0, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724515200.0, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724515200.0,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19]], [[1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19]], [[1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                            1724342400.19, 1724342400.19]], [[1724342400.19]],
                          [[1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19]], [
                              [1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19, 1724342400.19,
                               1724342400.19]], [[1724342400.19, 1724342400.19]], [[1724342400.19]],
                          [[1724342400.19, 1724342400.19]]]
    time_window_execution_time = 80.0
    is_split_vehicle = 0.0
    ems_floor = [['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'],
                 ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'],
                 ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'],
                 ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'],
                 ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'],
                 ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02'], ['02']]
    zz_floor = [['02'], ['02'], ['02'], ['02'], ['02'], ['01'], ['01'], ['01'], ['02'], ['01'], ['02'], ['02'], ['02'],
                ['01'], ['02'], ['02'], ['02'], ['01'], ['02'], ['02'], ['02'], ['02'], ['01'], ['01'], ['02'], ['02'],
                ['02'], ['02'], ['02'], ['02'], ['02'], ['01'], ['02'], ['01'], ['01'], ['02'], ['02'], ['02'], ['02']]
    floor_speed_map = {'03': 0.05555555555555555, '02': 0.05555555555555555, 'plt': 0.05555555555555555,
                       '01': 0.027777777777777776}
    floor_port_num_map = {'03': 8, '02': 6, 'plt': 3, '01': 2}
    floor_delivery_num_map = {'03': 8, '02': 6, 'plt': 10, '01': 2}
    port_assignment_map = {'02': [[3, 80], [2, 30]], '01': [[2, 30]], '03': [[2, 30]]}

    end_solution_x_total, solution_bool_sub_job, solution_bool_C, end_sxt, sbsj, sbc, car, job_re, job_total, \
        job_type_total, job_se_total, job_se_type_total, goods_num, total_d_num, total_d_goods, zz_real, no_car_re, no_job_data_re = main_fun(
        ems_goods_num, ems_begin_time, ems_end_time,
        ems_job_type, ems_pcs_num, zz_goods_num, zz_begin_time, zz_end_time, zz_job_type, zz_pcs_num,
        cl_pallet_list, zz_cl_pallet_list, vehicle_pallet_list,
        zz_vehicle_pallet_list, pallet_to_case_list, zz_pallet_to_case_list, time_windows,
        dis, zz_car_list, time_window_execution_time, time_window_execution_time, ems_deliver_interval_list,
        zz_deliver_interval_list, ems_priority_list, zz_priority_list, deliver_plan_time, detail_port_num,
        detail_id_arr,
        insert_time, global_time, box_flow_value,
        ems_detail_add_date, zz_detail_add_date, is_split_vehicle,
        ems_floor, zz_floor, floor_speed_map, floor_port_num_map,
        floor_delivery_num_map, port_assignment_map, logger=Logger)

    print("end_solution_x_total: ", end_solution_x_total)
    print("solution_bool_sub_job: ", solution_bool_sub_job)
    print("solution_bool_C: ", solution_bool_C)
    print("end_sxt: ", end_sxt)
    print("sbsj: ", sbsj)
    print("sbc: ", sbc)
    print("car: ", car)
    print("job_re: ", job_re)
    print("job_total: ", job_total)
    print("job_type_total: ", job_type_total)
    print("job_se_total: ", job_se_total)
    print("job_se_type_total: ", job_se_type_total)
    print("goods_num: ", goods_num)
    print("total_d_num: ", total_d_num)
    print("total_d_goods: ", total_d_goods)
    print("zz_real: ", zz_real)
    print("no_car_re: ", no_car_re)
    print("no_job_data_re", no_job_data_re)